{"record":{"id":"536dea6e95214910","repo":"hashicorp/nomad","slug":"no-signed-workload-identity-available","errorCode":null,"errorMessage":"no signed workload identity available","messagePattern":"no signed workload identity available","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocrunner/taskrunner/vault_hook.go","lineNumber":383,"sourceCode":"}\n\n// deriveVaultTokenJWT returns a Vault ACL token using JWT auth login.\nfunc (h *vaultHook) deriveVaultTokenJWT(ctx context.Context) (string, int, error) {\n\t// Retrieve signed identity.\n\tsigned, err := h.widmgr.Get(structs.WIHandle{\n\t\tIdentityName:       h.widName,\n\t\tWorkloadIdentifier: h.task.Name,\n\t\tWorkloadType:       structs.WorkloadTypeTask,\n\t})\n\tif err != nil {\n\t\treturn \"\", 0, structs.NewRecoverableError(\n\t\t\tfmt.Errorf(\"failed to retrieve signed workload identity: %w\", err),\n\t\t\ttrue,\n\t\t)\n\t}\n\tif signed == nil {\n\t\treturn \"\", 0, structs.NewRecoverableError(\n\t\t\terrors.New(\"no signed workload identity available\"),\n\t\t\tfalse,\n\t\t)\n\t}\n\n\trole := h.vaultConfig.Role\n\tif h.vaultBlock.Role != \"\" {\n\t\trole = h.vaultBlock.Role\n\t}\n\n\t// Derive Vault token with signed identity.\n\ttoken, renewable, leaseDuration, err := h.client.DeriveTokenWithJWT(ctx, vaultclient.JWTLoginRequest{\n\t\tJWT:       signed.JWT,\n\t\tRole:      role,\n\t\tNamespace: h.vaultBlock.Namespace,\n\t})\n\tif err != nil {\n\t\treturn \"\", 0, structs.WrapRecoverable(\n\t\t\tfmt.Sprintf(\"failed to derive Vault token for identity %s: %v\", h.widName, err),","sourceCodeStart":365,"sourceCodeEnd":401,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocrunner/taskrunner/vault_hook.go#L365-L401","documentation":"Nomad's Vault hook fails with 'no signed workload identity available' when deriving a Vault login JWT for workload identity-based auth (Vault 1.16+/JWT auth) and the allocrunner returned a nil signed identity without an error. Unlike the empty-string retrieval error above, this indicates the identity store produced nothing, and it is returned as a non-recoverable error, so the task will not retry automatically.","triggerScenarios":"deriveVaultTokenJWT calls the workload identity signer during token derivation; the signer returns success but a nil identity — e.g. the task has no matching signed identity minted (missing/incorrect vault block role wiring, identity not yet issued for the alloc) despite the vault block requesting WI auth.","commonSituations":"Nomad client older than the workload-identity feature or Vault cluster not configured for Nomad JWT auth; the vault block lacks a matching workload identity audience/role on the client; race where the task starts before its identity is signed; job specifies vault role but the client's vault config doesn't enable WI-based tokens.","solutions":["Ensure the Nomad client version supports Vault workload identities and the client's vault config has the correct default cluster/jwt auth setup","Check that the job's vault block and the Vault role (bound_audiences / Nomad audience) line up so a signed identity is minted for the alloc","Resubmit the job / restart the allocation so identities are (re)issued, then check alloc events for recovery","Fall back to legacy vault token derivation (vault token policy) if your Vault/Nomad versions don't support WI auth","Inspect agent logs around deriveVaultToken for the earlier 'failed to retrieve signed workload identity' error to find the root cause"],"exampleFix":"// before (job)\nvault {\n  role = \"web\" // no matching signed identity minted\n}\n// after: use policies or ensure role/audience configured\nvault {\n  policies = [\"web-read\"]\n  // or ensure nomad client vault config and Vault JWT auth role 'nomad-workloads' includes audience for this cluster\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"jwt, ttl, err := h.deriveVaultTokenJWT(ctx, nil)\nif err != nil {\n    var recov *structs.RecoverableError\n    if errors.As(err, &recov) && recov.IsRecoverable() {\n        return retryWithBackoff(err) // only recoverable errors retry\n    }\n    if strings.Contains(err.Error(), \"no signed workload identity available\") {\n        return fmt.Errorf(\"workload identity not issued; check nomad/vault WI auth config: %w\", err)\n    }\n    return err\n}","preventionTips":["Verify Nomad client and Vault both support workload-identity auth before enabling it","Confirm the Vault JWT auth role's bound audiences match the Nomad cluster identity","Check alloc events and agent logs for identity issuance before task start","Keep a legacy vault policies fallback configured while migrating to WI auth"],"tags":["nomad","vault","workload-identity","jwt","auth"],"backgroundTag":"no-signed-workload-identity","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"}