{"record":{"id":"9cb2fe61e0714b7c","repo":"hashicorp/nomad","slug":"no-identities-to-sign","errorCode":null,"errorMessage":"no identities to sign","messagePattern":"no identities to sign","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/widmgr/signer.go","lineNumber":69,"sourceCode":"}\n\n// SetNodeIdentityToken fulfills the NodeIdentityHandler interface, allowing\n// the client to update the node identity token used for RPC calls when it is\n// renewed.\nfunc (s *Signer) SetNodeIdentityToken(token string) { s.nodeIdentityToken.Store(token) }\n\n// SignIdentities wraps the Alloc.SignIdentities RPC and retrieves signed\n// workload identities. The minIndex should be set to the lowest allocation\n// CreateIndex to ensure that the server handling the request isn't so stale\n// that it doesn't know the allocation exist (and therefore rejects the signing\n// requests).\n//\n// Since a single rejection causes an error to be returned, SignIdentities\n// should currently only be used when requesting signed identities for a single\n// allocation.\nfunc (s *Signer) SignIdentities(minIndex uint64, req []*structs.WorkloadIdentityRequest) ([]*structs.SignedWorkloadIdentity, error) {\n\tif len(req) == 0 {\n\t\treturn nil, fmt.Errorf(\"no identities to sign\")\n\t}\n\n\t// Default to using the node secret, but if the node identity token is set,\n\t// this will be used instead. This handles the case where the node is\n\t// upgraded before the Nomad servers and should be removed in Nomad 1.13.\n\tauthToken := s.nodeSecret\n\n\tif id := s.nodeIdentityToken.Load(); id != nil {\n\t\tauthToken = id.(string)\n\t}\n\n\targs := structs.AllocIdentitiesRequest{\n\t\tIdentities: req,\n\t\tQueryOptions: structs.QueryOptions{\n\t\t\tRegion: s.region,\n\n\t\t\t// Unlike other RPCs, this one doesn't care about \"subsequent\n\t\t\t// modifications\" after an index. We only want to ensure the state","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/widmgr/signer.go#L51-L87","documentation":"Signer.SignIdentities validates that the caller passed at least one WorkloadIdentityRequest; an empty request slice is a programming error, so it fails fast with this message instead of making a pointless RPC to the servers.","triggerScenarios":"Calling SignIdentities(minIndex, req) with req == nil or len(req) == 0 — e.g. an allocation with no workload identities, or a caller building the request slice from an empty filtered set.","commonSituations":"Tasks with no workload_identity blocks; a bug where identities were filtered out earlier; tests constructing a Signer and calling it with no requests.","solutions":["Ensure the caller only invokes SignIdentities when the allocation has at least one workload identity.","Filter/log allocations lacking identities before requesting signing.","Check upstream code that builds the []*structs.WorkloadIdentityRequest slice for an over-aggressive filter."],"exampleFix":"// before\nsigned, err := signer.SignIdentities(0, reqs) // reqs may be empty\n// after\nif len(reqs) == 0 {\n    return nil\n}\nsigned, err := signer.SignIdentities(0, reqs)","handlingStrategy":"validation","validationCode":"if len(reqs) == 0 {\n    return nil // nothing to sign; skip the RPC entirely\n}\nsigned, err := signer.SignIdentities(minIndex, reqs)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only call SignIdentities for allocations that declare workload identities","Assert request slice non-empty in callers/tests","Check identity-filtering logic upstream"],"tags":["workload-identity","validation","nomad"],"backgroundTag":"empty-request","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"}