{"record":{"id":"c39a1f81695809ee","repo":"hashicorp/nomad","slug":"invalid-maxtokenttl-value-s-should-be-between","errorCode":null,"errorMessage":"invalid MaxTokenTTL value '%s' (should be between %s and %s)","messagePattern":"invalid MaxTokenTTL value '(.+?)' \\(should be between (.+?) and (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/acl.go","lineNumber":1448,"sourceCode":"\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"invalid name '%s'\", a.Name))\n\t}\n\n\tif !slices.Contains([]string{ACLAuthMethodTokenLocalityLocal, ACLAuthMethodTokenLocalityGlobal}, a.TokenLocality) {\n\t\tmErr.Errors = append(\n\t\t\tmErr.Errors, fmt.Errorf(\"invalid token locality '%s'\", a.TokenLocality))\n\t}\n\n\tif !slices.Contains(ValidACLAuthMethodTypes, a.Type) {\n\t\tmErr.Errors = append(\n\t\t\tmErr.Errors, fmt.Errorf(\"invalid token type '%s'\", a.Type))\n\t}\n\n\tif err := a.Config.Validate(a.Type); err != nil {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\"invalid config: %w\", err))\n\t}\n\n\tif minTTL > a.MaxTokenTTL || a.MaxTokenTTL > maxTTL {\n\t\tmErr.Errors = append(mErr.Errors, fmt.Errorf(\n\t\t\t\"invalid MaxTokenTTL value '%s' (should be between %s and %s)\",\n\t\t\ta.MaxTokenTTL.String(), minTTL.String(), maxTTL.String()))\n\t}\n\n\treturn mErr.ErrorOrNil()\n}\n\n// Sanitize returns a copy of the ACLAuthMethod with any secrets redacted\nfunc (a *ACLAuthMethod) Sanitize() *ACLAuthMethod {\n\tif a == nil || a.Config == nil {\n\t\treturn a\n\t}\n\t// copy to ensure we do not mutate a pointer pulled directly out of state.\n\tclean := a.Copy()\n\t// clean nested structs here, so it's obvious what all is being cleaned\n\t// in one spot, rather than follow a stack of sanitization calls.\n\tif clean.Config.OIDCClientSecret != \"\" {\n\t\tclean.Config.OIDCClientSecret = \"redacted\"","sourceCodeStart":1430,"sourceCodeEnd":1466,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/acl.go#L1430-L1466","documentation":"ACLAuthMethod.Validate() rejects MaxTokenTTL when it is not within [minTTL, maxTTL], the bounds supplied by the server (system defaults or agent config). Both the error message and bounds are formatted with time.Duration.String().","triggerScenarios":"Upserting an ACL auth method whose MaxTokenTTL is below the server minimum or above the server maximum (e.g. 1s when min is 1m, or 0/8760h when the configured max is 24h). Also triggered when minTTL > MaxTokenTTL with a zero MaxTokenTTL where a nonzero is required.","commonSituations":"Setting MaxTokenTTL: \"0s\" expecting 'no expiry'; guessing TTLs in a config where the operator changed the server's default/max ACL token TTLs; unit mistakes like \"2h\" vs \"2m\".","solutions":["Set MaxTokenTTL between the server's min and max (check agent config: audit the ACL token TTL defaults, e.g. 1m–24h).","Read the error message bounds and align the value to them.","Set MaxTokenTTL explicitly instead of relying on zero-value; use time.Duration constants in Go.","If a longer TTL is genuinely needed, raise the server-side max token TTL config, then re-submit."],"exampleFix":"// before\nam.MaxTokenTTL = 0 // \"no expiry\"\n// after\nam.MaxTokenTTL = 24 * time.Hour","handlingStrategy":"validation","validationCode":"minTTL, maxTTL := 1*time.Minute, 24*time.Hour // confirm with server config\nif am.MaxTokenTTL < minTTL || am.MaxTokenTTL > maxTTL {\n\treturn fmt.Errorf(\"MaxTokenTTL %s outside [%s, %s]\", am.MaxTokenTTL, minTTL, maxTTL)\n}","typeGuard":null,"tryCatchPattern":"if err := am.Validate(minTTL, maxTTL); err != nil {\n\tif strings.Contains(err.Error(), \"invalid MaxTokenTTL\") {\n\t\t// parse bounds from message and clamp before retry\n\t}\n\treturn err\n}","preventionTips":["Never use zero MaxTokenTTL expecting 'unlimited'","Pull the real min/max from the server's ACL config rather than guessing","Use time.Duration literals; double-check h vs m units"],"tags":["acl","ttl","validation","nomad"],"backgroundTag":"ttl-out-of-range","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"}