{"record":{"id":"51968305695cac3d","repo":"hashicorp/nomad","slug":"unable-to-process-acltoken-w","errorCode":null,"errorMessage":"unable to process ACLToken: %w","messagePattern":"unable to process ACLToken: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocrunner/consul_hook.go","lineNumber":346,"sourceCode":"\ntype resourcesBackend struct {\n\tallocID       string\n\thookResources *cstructs.AllocHookResources\n\tdb            cstate.StateDB\n}\n\nfunc newResourcesBackend(allocID string, hr *cstructs.AllocHookResources, db cstate.StateDB) *resourcesBackend {\n\treturn &resourcesBackend{\n\t\tallocID:       allocID,\n\t\thookResources: hr,\n\t\tdb:            db,\n\t}\n}\n\nfunc decodeACLToken(b64ACLToken string, token *consulapi.ACLToken) error {\n\tdecodedBytes, err := base64.StdEncoding.DecodeString(b64ACLToken)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to process ACLToken: %w\", err)\n\t}\n\n\tif len(decodedBytes) != 0 {\n\t\tif err := json.Unmarshal(decodedBytes, token); err != nil {\n\t\t\treturn fmt.Errorf(\"unable to unmarshal ACLToken: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc encodeACLToken(token *consulapi.ACLToken) (string, error) {\n\tjsonBytes, err := json.Marshal(token)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"unable to marshal ACL token: %w\", err)\n\t}\n\n\treturn base64.StdEncoding.EncodeToString(jsonBytes), nil","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocrunner/consul_hook.go#L328-L364","documentation":"decodeACLToken base64-decodes a stored Consul ACL token (from client state / hook resources); if base64.StdEncoding.DecodeString fails, it returns 'unable to process ACLToken: %w'. The stored token blob is not valid base64, indicating corrupted or malformed persisted state.","triggerScenarios":"loadAllocTokens reads a b64-encoded ACL token from hook resources/state that fails base64 decoding — e.g. hand-edited state, truncated data-dir files, or a token stored by incompatible serialization.","commonSituations":"Corrupted client data dir after disk full/crash; manual editing or migration of nomad client state files; restoring state from a different Nomad version.","solutions":["Verify the underlying base64 error in the log to confirm corruption vs encoding variant (url-safe vs std encoding)","Stop the allocation and clear its client state so tokens are re-derived fresh (token loss is safe; Consul re-login will mint new ones)","Check disk health and that the client data dir is not being modified externally","If reproducible, file a Nomad issue with the Nomad version and how the state was produced"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if b64ACLToken != \"\" {\n    if _, err := base64.StdEncoding.DecodeString(b64ACLToken); err != nil {\n        return fmt.Errorf(\"stored ACL token is not valid base64, discarding: %w\", err)\n    }\n}","typeGuard":"func isBase64(s string) bool {\n    _, err := base64.StdEncoding.DecodeString(s)\n    return err == nil\n}","tryCatchPattern":"token := &consulapi.ACLToken{}\nif err := decodeACLToken(b64ACLToken, token); err != nil {\n    h.logger.Warn(\"stored consul token unreadable, re-deriving\", \"error\", err)\n    token = nil // proceed with fresh JWT login instead of failing\n}","preventionTips":["Never hand-edit Nomad client state files","Protect the client data dir from disk-full and crash corruption; monitor disk health","When migrating clients, let allocations reschedule instead of copying state","On decode failure, fall back to re-deriving tokens rather than failing the hook"],"tags":["nomad","consul","acl-token","base64","state-corruption"],"backgroundTag":"base64-decode-failed","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"}