hashicorp/nomad · error
ACL token not found
Error message
ACL token not found
What it means
ErrTokenNotFound is a sentinel (nomad/structs/errors.go:56) returned when an ACL token (or equivalent credential) cannot be resolved for an RPC. It surfaces from token/role resolution paths (resolveTokenAndACL, ACL role handlers) and from the client ACL layer (client/acl.go:82) when a workload identity carries neither an ACLToken nor claims. The HTTP API maps it to a 403 response (command/agent/http.go:762).
Source
Thrown at nomad/structs/errors.go:56
errRPCCodedErrorPrefix = "RPC Error:: " errDeploymentTerminalNoCancel = "can't cancel terminal deployment" errDeploymentTerminalNoFail = "can't fail terminal deployment" errDeploymentTerminalNoPause = "can't pause terminal deployment" errDeploymentTerminalNoPromote = "can't promote terminal deployment" errDeploymentTerminalNoResume = "can't resume terminal deployment" errDeploymentTerminalNoUnblock = "can't unblock terminal deployment" errDeploymentTerminalNoRun = "can't run terminal deployment" errDeploymentTerminalNoSetHealth = "can't set health of allocations for a terminal deployment" errDeploymentRunningNoUnblock = "can't unblock running deployment" ) var ( ErrNoLeader = errors.New(errNoLeader) ErrNotReadyForConsistentReads = errors.New(errNotReadyForConsistentReads) ErrNoRegionPath = errors.New(errNoRegionPath) ErrTokenNotFound = errors.New(errTokenNotFound) ErrTokenExpired = errors.New(errTokenExpired) ErrTokenInvalid = errors.New(errTokenInvalid) ErrPermissionDenied = errors.New(errPermissionDenied) ErrJobRegistrationDisabled = errors.New(errJobRegistrationDisabled) ErrNoNodeConn = errors.New(errNoNodeConn) ErrUnknownMethod = errors.New(errUnknownMethod) ErrUnknownNomadVersion = errors.New(errUnknownNomadVersion) ErrNodeLacksRpc = errors.New(errNodeLacksRpc) ErrMissingAllocID = errors.New(errMissingAllocID) ErrIncompatibleFiltering = errors.New(errIncompatibleFiltering) ErrMalformedChooseParameter = errors.New(errMalformedChooseParameter) // ErrResultPaginatorCreation is returned by list RPC handlers when the // result paginator cannot be built, for example when the server cannot // evaluate a requested filter expression. api.ResultPaginatorErrorContent // duplicates its message so the CLI can match it without importing structs. // Keep the two in sync. ErrResultPaginatorCreation = errors.New(errResultPaginatorCreation)
View on GitHub (pinned to 482b49bf1a)
Solutions
- Generate a new token with `nomad acl token create` (or via SSO/login for workload identities) and update the client's credentials
- Verify the token value is complete and correctly set (NOMAD_TOKEN env, -token flag, or agent config) — check for truncation or whitespace
- If using workload identities, ensure the job/task identity is configured so Claims are present, or that the ACL token was injected into the alloc
- Check `nomad acl token list` (with a management token) to confirm the token still exists and is not expired
Example fix
// before
client.SetToken(os.Getenv("NOMAD_TOKEN")) // stale/revoked token
// after
token := os.Getenv("NOMAD_TOKEN")
if token == "" {
token = fetchNewTokenFromVault() // re-issue from secure store
}
client.SetToken(token) Defensive patterns
Strategy: try-catch
Validate before calling
// verify the token resolves before making calls
_, _, err := client.ACL().GetToken(tokenID)
if err != nil {
return fmt.Errorf("token %q is invalid or deleted; re-issue credentials", tokenID)
} Type guard
func isTokenNotFound(err error) bool {
return errors.Is(err, structs.ErrTokenNotFound) || strings.Contains(err.Error(), structs.ErrTokenNotFound.Error())
} Try / catch
resp, err := client.System().ListMembers()
if err != nil {
if isTokenNotFound(err) {
// HTTP 403 path: refresh credentials and retry once
client.SetToken(rotateToken())
resp, err = client.System().ListMembers()
}
if err != nil {
return err
}
} Prevention
- Store tokens in a secret manager and refresh them before expiry rather than hardcoding
- Handle 403 with token-not-found distinctly from permission-denied: one means re-auth, the means re-authz
- For workload identities, ensure jobs declare identities so Claims are attached to client RPCs
- Audit token lifetimes (TTLs) and automate renewal/rotation in CI/CD pipelines
When it happens
Trigger: Passing an `X-Nomad-Token` whose SecretID doesn't exist (expired/deleted token); empty or missing token where ACLs are enabled; client RPC with a workload identity lacking both ACLToken and Claims; referencing a token that was revoked or purged from state store.
Common situations: Stale NOMAD_TOKEN env var or CLI config after token rotation; CI/CD using a token deleted by policy; upgrading workloads to workload identities while the old ACL token was revoked; copy-pasting a truncated secret ID.
Related errors
- ACL token not found or invalid workload identity: %v
- token name too long
- client token missing policies or roles
- management token cannot be associated with policies or roles
- token type must be client or management
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/0bb58eb14e0c308d.
Report an issue: GitHub.