{"record":{"id":"5016f82ea091f119","repo":"hashicorp/nomad","slug":"acl-token-lookup-failed-missing-secret-id","errorCode":null,"errorMessage":"acl token lookup failed: missing secret id","messagePattern":"acl token lookup failed: missing secret id","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/state/state_store.go","lineNumber":6466,"sourceCode":"\tif existing == nil {\n\t\treturn nil, nil\n\t}\n\n\t// Assert the token type which allows us to perform additional work on the\n\t// token that is needed before returning the call.\n\ttoken := existing.(*structs.ACLToken)\n\n\t// Handle potential staleness of ACL role links.\n\tif token, err = s.fixTokenRoleLinks(txn, token); err != nil {\n\t\treturn nil, err\n\t}\n\treturn token, nil\n}\n\n// ACLTokenBySecretID is used to lookup a token by secret ID\nfunc (s *StateStore) ACLTokenBySecretID(ws memdb.WatchSet, secretID string) (*structs.ACLToken, error) {\n\tif secretID == \"\" {\n\t\treturn nil, fmt.Errorf(\"acl token lookup failed: missing secret id\")\n\t}\n\n\ttxn := s.db.ReadTxn()\n\n\twatchCh, existing, err := txn.FirstWatch(\"acl_token\", \"secret\", secretID)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"acl token lookup failed: %v\", err)\n\t}\n\tws.Add(watchCh)\n\n\t// If the existing token is nil, this indicates it does not exist in state.\n\tif existing == nil {\n\t\treturn nil, nil\n\t}\n\n\t// Assert the token type which allows us to perform additional work on the\n\t// token that is needed before returning the call.\n\ttoken := existing.(*structs.ACLToken)","sourceCodeStart":6448,"sourceCodeEnd":6484,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/state/state_store.go#L6448-L6484","documentation":"Validation error from StateStore.ACLTokenBySecretID: an empty secret ID was supplied. SecretID is the credential users authenticate with (the 'secret' index on acl_token), so the store rejects empty input before querying. Like 2747, it signals a caller-input problem.","triggerScenarios":"Calling ACLTokenBySecretID with \"\" — empty ACL token from a client request, unset environment/config value, or a handler that did not validate before store access.","commonSituations":"nomad CLI/jobs submitted with NOMAD_TOKEN=\"\"; API clients omitting X-Nomad-Token; plugins resolving tokens from empty fields; tests exercising the empty path.","solutions":["Guard with a non-empty check (after TrimSpace) before the store call.","Return a clear auth error (403/permission denied) at the RPC layer for missing tokens instead of the store sentinel.","Fix client configuration so the token is actually set (NOMAD_TOKEN, agent config, etc.)."],"exampleFix":"// before\ntoken, err := store.ACLTokenBySecretID(ws, header.Get(\"X-Nomad-Token\"))\n// after\nsecret := header.Get(\"X-Nomad-Token\")\nif secret == \"\" {\n    return structs.NewErrRPCCoded(403, \"Permission denied\")\n}\ntoken, err := store.ACLTokenBySecretID(ws, secret)","handlingStrategy":"validation","validationCode":"func canLookupBySecret(secretID string) bool {\n    return strings.TrimSpace(secretID) != \"\"\n}\n// before calling:\n// if !canLookupBySecret(secretID) { return errors.New(\"missing secret id\") }","typeGuard":"func hasSecretID(t *struct.ACLToken) bool {\n    return t != nil && t.SecretID != \"\"\n}","tryCatchPattern":"if secretID == \"\" {\n    return structs.NewErrRPCCoded(403, \"Permission denied\")\n}\ntoken, err := store.ACLTokenBySecretID(ws, secretID)\nif err != nil { return err }","preventionTips":["Ensure NOMAD_TOKEN / X-Nomad-Token is actually set in clients and CI","Trim and validate token strings before resolution","Fail closed (permission denied) on empty credentials at the handler layer","Cover the empty-secret path in auth middleware tests"],"tags":["nomad","state-store","acl","input-validation"],"backgroundTag":"missing-id-token","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"}