hashicorp/nomad · error

ACL token expired

Error message

ACL token expired

What it means

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.

Source

Thrown at nomad/structs/errors.go:57

	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

  1. Issue or obtain a fresh ACL token and retry the request
  2. Enable/configure token renewal if the client supports renewing short-lived tokens
  3. Use a non-expiring token for long-lived agents
  4. Synchronize clocks (NTP) if the token expired marginally earlier than expected

Example fix

// before
client ACL set-token old-expired-token
// after
nomad acl token create -ttl=1h -policy=write
nomad acl token update -accessor-id <accessor> -renew
Defensive patterns

Strategy: type-guard

Validate before calling

if token.ExpireTime != nil && token.ExpireTime.Before(time.Now()) {
    // token already expired; request a new one before calling the API
}

Type guard

func IsTokenExpired(t *api.ACLToken, now time.Time) bool {
    return t != nil && t.ExpireTime != nil && t.ExpireTime.Before(now.Add(-2 * time.Second))
}

Try / catch

acl, err := client.ACL().Info(token)
switch {
case errors.Is(err, structs.ErrTokenExpired):
    token = renewOrCreateToken(); retry()
case err != nil:
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/9186ad0b292f781d. Report an issue: GitHub.