{"record":{"id":"ae446eaceb4a5ef3","repo":"rancher/rancher","slug":"error-validating-ttl-against-default-and-max-w","errorCode":null,"errorMessage":"error validating ttl against default and max: %w","messagePattern":"error validating ttl against default and max: %w","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"pkg/auth/tokens/manager.go","lineNumber":108,"sourceCode":"\t}\n\n\treturn user.PrincipalIDs, nil\n}\n\n// createDerivedToken will create a jwt token for the authenticated user\nfunc (m *Manager) createDerivedToken(jsonInput clientv3.Token, tokenAuthValue string) (apiv3.Token, string, int, error) {\n\tlogrus.Debug(\"Create Derived Token Invoked\")\n\n\ttoken, _, err := m.GetToken(tokenAuthValue)\n\tif err != nil {\n\t\treturn apiv3.Token{}, \"\", http.StatusUnauthorized, err\n\t}\n\n\ttokenTTL, err := exttokenstore.IngestTTL(int64(jsonInput.TTLMillis),\n\t\tsettings.AuthTokenMaxTTLMinutes,\n\t\tsettings.AuthTokenDefaultTTLMinutes)\n\tif err != nil {\n\t\treturn apiv3.Token{}, \"\", http.StatusInternalServerError, fmt.Errorf(\"error validating ttl against default and max: %w\", err)\n\t}\n\n\tvar unhashedTokenKey string\n\tderivedToken := &apiv3.Token{\n\t\tUserPrincipal: token.GetUserPrincipal(),\n\t\tIsDerived:     true,\n\t\tTTLMillis:     tokenTTL,\n\t\tUserID:        token.GetUserID(),\n\t\tAuthProvider:  token.GetAuthProvider(),\n\t\tProviderInfo:  token.GetProviderInfo(),\n\t\tDescription:   jsonInput.Description,\n\t\tClusterName:   jsonInput.ClusterID,\n\t}\n\tderivedToken, unhashedTokenKey, err = m.createToken(derivedToken)\n\n\treturn *derivedToken, unhashedTokenKey, 0, err\n\n}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/rancher/rancher/blob/932558d4e68565aff2d2f36e89ec4a391b06e7c5/pkg/auth/tokens/manager.go#L90-L126","documentation":"Raised in Manager.createDerivedToken (pkg/auth/tokens/manager.go:108) when exttokenstore.IngestTTL fails while validating the requested token TTL. IngestTTL never rejects the request's own ttlMillis (0 means default, negative means infinite; both are clamped) — the only failure path is ParseTTLToMilliseconds erroring on the server settings auth-token-max-ttl-minutes or auth-token-default-ttl-minutes, whose values must be plain integer strings ('600', not '600m', '10h', or 'abc'). The handler converts this to HTTP 500.","triggerScenarios":"POST to create an API/derived token (e.g. v3/token via Rancher API or 'Create API Key' flow) while auth-token-max-ttl-minutes or auth-token-default-ttl-minutes holds a non-integer value; ParseTTLToDuration appends 'm' and time.ParseDuration fails on inputs like '600mm', '10hm', ''. Every token creation then 500s.","commonSituations":"Admin enters a duration with a unit suffix ('1440m', '24h') into the Rancher settings UI, which expects bare minutes; automation patches settings.management.cattle.io with formatted durations; setting left empty after a partial upgrade.","solutions":["Reset both settings to plain integer minute strings: kubectl patch settings.auth-token-max-ttl-minutes and settings.auth-token-default-ttl-minutes (or the UI: Global Settings) — e.g. '0' for unlimited max, '600' for 10h default","Confirm with: kubectl get settings auth-token-max-ttl-minutes auth-token-default-ttl-minutes -o jsonpath='{..value}'","Retry token creation after correcting values; no restart is needed since settings are read live","Note the requested TTLMillis itself cannot cause this error — do not waste time changing the request TTL"],"exampleFix":"# before (values with units — every token create returns 500)\nkubectl get settings auth-token-max-ttl-minutes auth-token-default-ttl-minutes -o custom-columns=NAME:.metadata.name,VALUE:.value\n# auth-token-max-ttl-minutes   1440m\n\n# after (plain integer minutes)\nkubectl patch setting auth-token-max-ttl-minutes --type=merge -p '{\"value\":\"1440\"}'\nkubectl patch setting auth-token-default-ttl-minutes --type=merge -p '{\"value\":\"600\"}'","handlingStrategy":"validation","validationCode":"// pre-flight: both TTL settings must parse as plain integer minutes\nfor _, s := range []settings.Setting{settings.AuthTokenMaxTTLMinutes, settings.AuthTokenDefaultTTLMinutes} {\n\tif _, err := exttokenstore.ParseTTLToMilliseconds(s); err != nil {\n\t\treturn fmt.Errorf(\"fix setting %s: %w\", s.Name, err)\n\t}\n}","typeGuard":"func validTTLSetting(v string) bool {\n\tn, err := strconv.ParseInt(v, 10, 64)\n\treturn err == nil && n >= 0\n}","tryCatchPattern":"if _, _, code, err := m.createDerivedToken(input, auth); err != nil {\n\tif code == http.StatusInternalServerError && strings.Contains(err.Error(), \"validating ttl\") {\n\t\talertOnMisconfiguredTTSettings() // server-side fix required, do not retry\n\t}\n}","preventionTips":["Enter TTL settings as bare integers (minutes) — never '600m', '24h', or blank","Add CI validation on settings manifests that patch auth-token-*-minutes","Know the encoding: 0 = use default / no max; negative = infinite; requests are clamped, never rejected — only the settings themselves can break this path"],"tags":["auth","token","ttl","settings","server-error","rancher","go"],"backgroundTag":null,"analyzedSha":"932558d4e68565aff2d2f36e89ec4a391b06e7c5","analyzedAt":"2026-08-16T04:37:02.125Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}