{"record":{"id":"9186ad0b292f781d","repo":"hashicorp/nomad","slug":"acl-token-expired","errorCode":null,"errorMessage":"ACL token expired","messagePattern":"ACL token expired","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/errors.go","lineNumber":57,"sourceCode":"\terrRPCCodedErrorPrefix = \"RPC Error:: \"\n\n\terrDeploymentTerminalNoCancel    = \"can't cancel terminal deployment\"\n\terrDeploymentTerminalNoFail      = \"can't fail terminal deployment\"\n\terrDeploymentTerminalNoPause     = \"can't pause terminal deployment\"\n\terrDeploymentTerminalNoPromote   = \"can't promote terminal deployment\"\n\terrDeploymentTerminalNoResume    = \"can't resume terminal deployment\"\n\terrDeploymentTerminalNoUnblock   = \"can't unblock terminal deployment\"\n\terrDeploymentTerminalNoRun       = \"can't run terminal deployment\"\n\terrDeploymentTerminalNoSetHealth = \"can't set health of allocations for a terminal deployment\"\n\terrDeploymentRunningNoUnblock    = \"can't unblock running deployment\"\n)\n\nvar (\n\tErrNoLeader                   = errors.New(errNoLeader)\n\tErrNotReadyForConsistentReads = errors.New(errNotReadyForConsistentReads)\n\tErrNoRegionPath               = errors.New(errNoRegionPath)\n\tErrTokenNotFound              = errors.New(errTokenNotFound)\n\tErrTokenExpired               = errors.New(errTokenExpired)\n\tErrTokenInvalid               = errors.New(errTokenInvalid)\n\tErrPermissionDenied           = errors.New(errPermissionDenied)\n\tErrJobRegistrationDisabled    = errors.New(errJobRegistrationDisabled)\n\tErrNoNodeConn                 = errors.New(errNoNodeConn)\n\tErrUnknownMethod              = errors.New(errUnknownMethod)\n\tErrUnknownNomadVersion        = errors.New(errUnknownNomadVersion)\n\tErrNodeLacksRpc               = errors.New(errNodeLacksRpc)\n\tErrMissingAllocID             = errors.New(errMissingAllocID)\n\tErrIncompatibleFiltering      = errors.New(errIncompatibleFiltering)\n\tErrMalformedChooseParameter   = errors.New(errMalformedChooseParameter)\n\n\t// ErrResultPaginatorCreation is returned by list RPC handlers when the\n\t// result paginator cannot be built, for example when the server cannot\n\t// evaluate a requested filter expression. api.ResultPaginatorErrorContent\n\t// duplicates its message so the CLI can match it without importing structs.\n\t// Keep the two in sync.\n\tErrResultPaginatorCreation = errors.New(errResultPaginatorCreation)\n","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/errors.go#L39-L75","documentation":"ErrTokenExpired is a sentinel error in nomad/structs indicating the ACL token (or workload identity) presented has passed its expiration time. The servers return it during authentication when the token's ExpireTime is in the past (with a 2-second clock-skew allowance on the client side). It means the credential itself is structurally valid but no longer usable.","triggerScenarios":"Any RPC that authenticates via resolveTokenAndACL, Authenticate, resolveTokenFromSnapshotCache, or resolveSecretToken when the token/identity's IsExpired(now+2s) check is true — e.g. calling an API with a token created with a TTL that has elapsed.","commonSituations":"Long-running agents or CI jobs started with a short-lived ACL token or workload identity whose TTL expired mid-run; clock skew between client and servers (partially mitigated by the 2s skew buffer); tokens issued by Vault-style short-TTL workflows not being renewed.","solutions":["Issue or obtain a fresh ACL token and retry the request","Enable/configure token renewal if the client supports renewing short-lived tokens","Use a non-expiring token for long-lived agents","Synchronize clocks (NTP) if the token expired marginally earlier than expected"],"exampleFix":"// before\nclient ACL set-token old-expired-token\n// after\nnomad acl token create -ttl=1h -policy=write\nnomad acl token update -accessor-id <accessor> -renew","handlingStrategy":"type-guard","validationCode":"if token.ExpireTime != nil && token.ExpireTime.Before(time.Now()) {\n    // token already expired; request a new one before calling the API\n}","typeGuard":"func IsTokenExpired(t *api.ACLToken, now time.Time) bool {\n    return t != nil && t.ExpireTime != nil && t.ExpireTime.Before(now.Add(-2 * time.Second))\n}","tryCatchPattern":"acl, err := client.ACL().Info(token)\nswitch {\ncase errors.Is(err, structs.ErrTokenExpired):\n    token = renewOrCreateToken(); retry()\ncase err != nil:\n    return err\n}","preventionTips":["Use non-expiring tokens for long-lived agents and CI workers","Renew short-lived tokens on a schedule well before TTL expiry","Monitor token ExpireTime and alert before expiry","Keep clocks synchronized with NTP across clients and servers"],"tags":["acl","auth","nomad","token-expiry"],"backgroundTag":"acl-token-expired","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"}