{"record":{"id":"23b53af4a7ee01ec","repo":"hashicorp/nomad","slug":"bad-length-d","errorCode":null,"errorMessage":"bad length: %d","messagePattern":"bad length: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"info","filePath":"helper/raftutil/msgpack.go","lineNumber":57,"sourceCode":"// maybeDecodeTime returns a time.Time representation if the string represents a msgpack\n// representation of a date.\nfunc maybeDecodeTime(v string) (*time.Time, error) {\n\tif isASCII(v) {\n\t\treturn nil, fmt.Errorf(\"simple ascii string\")\n\t}\n\n\ttt := &time.Time{}\n\tvar err error\n\n\terr = tt.UnmarshalBinary([]byte(v))\n\tif err == nil {\n\t\treturn tt, nil\n\t}\n\n\tswitch len(v) {\n\tcase 4, 8, 12:\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"bad length: %d\", len(v))\n\t}\n\n\tvar nb bytes.Buffer\n\terr = codec.NewEncoder(&nb, structs.MsgpackHandle).Encode(v)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\terr = codec.NewDecoder(&nb, structs.MsgpackHandle).Decode(tt)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn tt, nil\n}\n\n// isASCII returns true if all string characters are ASCII characters\nfunc isASCII(s string) bool {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/raftutil/msgpack.go#L39-L75","documentation":"maybeDecodeTime heuristically converts strings that look like binary msgpack-encoded time.Time values back into time.Time when walking snapshot data. A string that is non-ASCII (so a candidate) but whose length is not 4, 8, or 12 bytes cannot be any known msgpack time encoding, so it returns \"bad length: %d\". This is normal control flow: fixTime treats the error as 'not a time' and leaves the value untouched.","triggerScenarios":"fixTime iterates map values decoded from a snapshot and passes any non-ASCII string to maybeDecodeTime; the string fails time.Time.UnmarshalBinary and its byte length is not 4, 8, or 12 (e.g. any non-ASCII UTF-8 string like accented names or emoji).","commonSituations":"Redacting or inspecting snapshots (RedactSnapshot path) where job/variable/node payloads contain non-ASCII strings that are not timestamps — this is expected and harmless; only a bug if genuinely encoded times are being dropped.","solutions":["No action needed: callers treat this error as 'value is not a timestamp' and leave the string as-is.","If a real time value is being missed, verify the snapshot's msgpack handle matches structs.MsgpackHandle so times encode in the expected 4/8/12-byte form.","If you call maybeDecodeTime directly, first check len(v) is 4, 8, or 12 to avoid the error entirely."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Only treat strings as candidate times if they are non-ASCII and a valid length\nfunc isCandidateTime(v string) bool {\n    if isASCII(v) { return false }\n    switch len(v) { case 4, 8, 12: return true }\n    return false\n}","typeGuard":"// Narrow decoded map values before use\nt, ok := val.(time.Time)\nif !ok {\n    if s, isStr := val.(string); isStr && isCandidateTime(s) {\n        if tt, err := maybeDecodeTime(s); err == nil && isReasonableTime(tt) { t, ok = *tt, true }\n    }\n}","tryCatchPattern":"if t, err := maybeDecodeTime(s); err == nil && isReasonableTime(t) {\n    m[k] = *t\n} // else: leave the original string; the error is an expected 'not a time' signal","preventionTips":["Treat this error as normal control flow — never log or fail on it in the fixTime path.","When calling maybeDecodeTime directly, pre-check len(v) ∈ {4,8,12}.","Always pair a successful decode with isReasonableTime to avoid absurd dates.","Ensure snapshots are encoded with structs.MsgpackHandle so times use the expected binary forms."],"tags":["msgpack","decoding","heuristic"],"backgroundTag":"msgpack-time-decode-mismatch","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}