{"record":{"id":"6667a9030759a43f","repo":"hashicorp/nomad","slug":"one-time-token-lookup-failed-missing-secret","errorCode":null,"errorMessage":"one-time token lookup failed: missing secret","messagePattern":"one-time token lookup failed: missing secret","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"nomad/state/state_store.go","lineNumber":6713,"sourceCode":"\treturn txn.Commit()\n}\n\n// oneTimeTokensExpiredTxn returns an iterator over all expired one-time tokens\nfunc (s *StateStore) oneTimeTokensExpiredTxn(txn *txn, ws memdb.WatchSet, timestamp time.Time) (memdb.ResultIterator, error) {\n\titer, err := txn.Get(\"one_time_token\", \"id\")\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"one-time token lookup failed: %v\", err)\n\t}\n\n\tws.Add(iter.WatchCh())\n\titer = memdb.NewFilterIterator(iter, expiredOneTimeTokenFilter(timestamp))\n\treturn iter, nil\n}\n\n// OneTimeTokenBySecret is used to lookup a token by secret\nfunc (s *StateStore) OneTimeTokenBySecret(ws memdb.WatchSet, secret string) (*structs.OneTimeToken, error) {\n\tif secret == \"\" {\n\t\treturn nil, fmt.Errorf(\"one-time token lookup failed: missing secret\")\n\t}\n\n\ttxn := s.db.ReadTxn()\n\n\twatchCh, existing, err := txn.FirstWatch(\"one_time_token\", \"secret\", secret)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"one-time token lookup failed: %v\", err)\n\t}\n\tws.Add(watchCh)\n\n\tif existing != nil {\n\t\treturn existing.(*structs.OneTimeToken), nil\n\t}\n\treturn nil, nil\n}\n\n// expiredOneTimeTokenFilter returns a filter function that returns only\n// expired one-time tokens","sourceCodeStart":6695,"sourceCodeEnd":6731,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/state/state_store.go#L6695-L6731","documentation":"OneTimeTokenBySecret refuses to query the state store when the provided secret is the empty string. Unlike other lookups that return nil,nil for missing values, an empty secret is treated as a caller error and raises immediately.","triggerScenarios":"Calling state store OneTimeTokenBySecret (or the HTTP endpoint that resolves an one-time token) with an empty/absent secret, e.g. a request body missing the OneTimeToken secret field.","commonSituations":"Automation submitting an empty one-time-token secret for variable decryption; a client that failed to fetch the one-time token first; older clients/workload drivers omitting the field.","solutions":["Ensure the caller generates a one-time token first (ACLToken OneTimeToken endpoint) and passes its Secret field","Add a non-empty check on the secret before invoking the lookup","Fix the client/request so the secret is included in the body","Check for version skew between client and server API fields"],"exampleFix":"// before\nott, err := state.OneTimeTokenBySecret(ws, token.Secret)\n// after\nif token == nil || token.Secret == \"\" {\n    return fmt.Errorf(\"no one-time token secret supplied\")\n}\nott, err := state.OneTimeTokenBySecret(ws, token.Secret)","handlingStrategy":"validation","validationCode":"if secret == \"\" {\n    return fmt.Errorf(\"one-time token secret must be provided before lookup\")\n}","typeGuard":"func hasOneTimeSecret(t *structs.OneTimeToken) bool { return t != nil && t.Secret != \"\" }","tryCatchPattern":"ott, err := state.OneTimeTokenBySecret(ws, secret)\nif err != nil && strings.Contains(err.Error(), \"missing secret\") {\n    return structs.NewErrRPCCoded(400, \"one-time token secret required\")\n}","preventionTips":["Always fetch a one-time token from the API before presenting its secret for decryption","Validate request bodies for required secret fields at the RPC boundary","Check client/server version skew on OneTimeToken fields"],"tags":["nomad","state-store","one-time-token","validation"],"backgroundTag":"missing-required-argument","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"}