{"record":{"id":"06b28c324a6d7cf9","repo":"hashicorp/nomad","slug":"unable-to-find-token-for-workload-q-and-identity","errorCode":null,"errorMessage":"unable to find token for workload %q and identity %q","messagePattern":"unable to find token for workload %q and identity %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/widmgr/widmgr.go","lineNumber":150,"sourceCode":"\t}\n\n\tgo m.renew()\n\n\treturn nil\n}\n\n// Get retrieves the latest signed identity or returns an error. It must be\n// called after Run and does not block.\n//\n// For retrieving tokens which might be renewed callers should use Watch\n// instead to avoid missing new tokens retrieved by Run between Get and Watch\n// calls.\nfunc (m *WIDMgr) Get(id structs.WIHandle) (*structs.SignedWorkloadIdentity, error) {\n\ttoken := m.get(id)\n\tif token == nil {\n\t\t// This is an error as every identity should have a token by the time Get\n\t\t// is called.\n\t\treturn nil, fmt.Errorf(\"unable to find token for workload %q and identity %q\", id.WorkloadIdentifier, id.IdentityName)\n\t}\n\n\treturn token, nil\n}\n\nfunc (m *WIDMgr) get(id structs.WIHandle) *structs.SignedWorkloadIdentity {\n\tm.lastTokenLock.RLock()\n\tdefer m.lastTokenLock.RUnlock()\n\n\treturn m.lastToken[id]\n}\n\n// Watch returns a channel that sends new signed identities until it is closed\n// due to shutdown. Must be called after Run.\n//\n// The caller must call the returned func to stop watching and ensure the\n// watched id actually exists, otherwise the channel never returns a result.\nfunc (m *WIDMgr) Watch(id structs.WIHandle) (<-chan *structs.SignedWorkloadIdentity, func()) {","sourceCodeStart":132,"sourceCodeEnd":168,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/widmgr/widmgr.go#L132-L168","documentation":"WIDMgr.Get is the synchronous accessor tasks use to obtain a signed identity token; it returns an error if no token is cached for the given WIHandle. By design every identity should have a token by the time Get is called, so this signals a lifecycle bug or premature access.","triggerScenarios":"Calling Get with a WIHandle whose WorkloadIdentifier/IdentityName was never requested (or whose token was fetched but not yet stored), or after signing failed and Run's refresh never populated the manager.","commonSituations":"Task hook calling Get before Run/getInitialIdentities completed; identity name typo or handle built from wrong workload; signing previously failed so nothing was cached; restart where state DB lost the token.","solutions":["Ensure Run() completed and signing succeeded before calling Get.","Verify the WIHandle matches exactly the workload identifier and identity name that were requested.","Check logs for earlier 'failed to fetch signed identities' errors indicating the manager never got tokens.","Restart the task/agent so identities are re-requested and cached."],"exampleFix":"// before\ntok, err := widMgr.Get(structs.WIHandle{WorkloadIdentifier: tgName, IdentityName: \"vault_token\"})\n// after\nhandle := alloc.TaskServicesWIHandleForIdentity(tgName, \"vault_token\") // derive from alloc, not hand-built\ntok, err := widMgr.Get(handle)\nif err != nil {\n    return fmt.Errorf(\"identity not yet available: %w\", err)\n}","handlingStrategy":"type-guard","validationCode":"// ensure the manager is ready before Get\nif !widMgr.Ready() { // or wait on a ready channel\n    return fmt.Errorf(\"widmgr not initialized\")\n}","typeGuard":"func tokenAvailable(m *WIDMgr, id structs.WIHandle) bool { return m.get(id) != nil }","tryCatchPattern":"tok, err := widMgr.Get(handle)\nif err != nil {\n    if strings.Contains(err.Error(), \"unable to find token\") {\n        // wait for renewal/signing, then retry once\n        time.Sleep(backoff)\n        tok, err = widMgr.Get(handle)\n    }\n    if err != nil { return err }\n}","preventionTips":["Build WIHandle from the allocation, never by hand","Wait for Run()/initial signing to complete before Get","Check for prior signing failures in logs"],"tags":["workload-identity","cache-miss","nomad"],"backgroundTag":"token-not-found","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"}