{"record":{"id":"5d20152cd28129f6","repo":"hashicorp/nomad","slug":"unexpected-ttl-type-v","errorCode":null,"errorMessage":"unexpected TTL type: %v","messagePattern":"unexpected TTL type: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/acl.go","lineNumber":2530,"sourceCode":"\t\t*Alias\n\t}{\n\t\tAlias: (*Alias)(a),\n\t}\n\tif err = json.Unmarshal(data, &aux); err != nil {\n\t\treturn err\n\t}\n\tif aux.TTL != nil {\n\t\tswitch v := aux.TTL.(type) {\n\t\tcase string:\n\t\t\tif v != \"\" {\n\t\t\t\tif a.TTL, err = time.ParseDuration(v); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\t\tcase float64:\n\t\t\ta.TTL = time.Duration(v)\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unexpected TTL type: %v\", v)\n\t\t}\n\t}\n\treturn nil\n}\n\n// ACLCreateClientIntroductionTokenResponse is the response object used within the ACL\n// client introduction RPC handler.\ntype ACLCreateClientIntroductionTokenResponse struct {\n\n\t// JWT is the signed identity token that can be used as an introduction\n\t// token for a new client node to register with the Nomad cluster.\n\tJWT string\n}\n","sourceCodeStart":2512,"sourceCodeEnd":2544,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/acl.go#L2512-L2544","documentation":"This error is returned by the SetahlTTL-style mapstructure decode hook / UnmarshalJSON helper in HashiCorp Nomad's ACL token struct when the TTL value supplied for an ACL token (e.g. a client token introduction/expiration TTL) arrives as a JSON/encoding type other than the accepted string-with-duration or float64 form. The decoder switches on the Go type of the raw value; float64 is cast to time.Duration nanoseconds, but any other type (bool, nil, string handled elsewhere) falls through to the default branch. It signals that the caller sent a structurally invalid TTL value for the ACL API.","triggerScenarios":"Calling the ACL token creation/introduction API (or feeding a Nomad config/JSON blob through structs.DecodeACLToken-style decoding) with a TTL field typed as something other than an accepted duration representation - e.g. a boolean, null, nested object, or array. Typically seen when an automation tool emits the wrong JSON type for the TTL field.","commonSituations":"Terraform/CLI tooling generating JSON with a wrong-typed TTL (e.g. \"ttl\": true or an object); template rendering producing quoted numbers where the decoder path doesn't accept strings; SDK clients marshaling Go ints (not float64) into a hook that only handles float64 after JSON decoding.","solutions":["Inspect the payload sent to the ACL API and set the TTL field to a valid duration string (e.g. \"30s\") or a plain JSON number.","Check for template/config generation bugs that emit the wrong JSON type (bool/null/object) for the TTL key.","Upgrade the Nomad client/SDK so the decode hook matches the server's accepted TTL formats.","If writing custom tooling, parse the value into time.Duration before submitting it."],"exampleFix":"// before\n{ \"Name\": \"deploy\", \"Type\": \"client\", \"TTL\": true }\n// after\n{ \"Name\": \"deploy\", \"Type\": \"client\", \"TTL\": \"30s\" }","handlingStrategy":"type-guard","validationCode":"if v, ok := rawTTL.(string); !ok && !isJSONNumber(rawTTL) {\n    return fmt.Errorf(\"TTL must be a duration string or number, got %T\", rawTTL)\n}","typeGuard":"func validTTL(v interface{}) bool {\n    switch v.(type) {\n    case string, float64, int64, int:\n        return true\n    default:\n        return false\n    }\n}","tryCatchPattern":"if err := token.Validate(); err != nil {\n    if strings.Contains(err.Error(), \"unexpected TTL type\") {\n        // reject payload, log the offending field type and re-serialize with a duration string\n    }\n    return err\n}","preventionTips":["Always send TTL as a Go-style duration string (\"30s\") in JSON payloads.","Never emit booleans, null, or nested objects for duration fields.","Marshal durations via time.Duration String() before serialization.","Add schema validation on client payloads before calling the ACL API."],"tags":["nomad","acl","json-decoding","type-mismatch"],"backgroundTag":"invalid-json-field-type","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"}