{"record":{"id":"5e756ee63fd3286e","repo":"hashicorp/nomad","slug":"no-one-time-token-returned","errorCode":null,"errorMessage":"no one-time token returned","messagePattern":"no one-time token returned","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/acl.go","lineNumber":220,"sourceCode":"// Self is used to query our own token\nfunc (a *ACLTokens) Self(q *QueryOptions) (*ACLToken, *QueryMeta, error) {\n\tvar resp ACLToken\n\twm, err := a.client.query(\"/v1/acl/token/self\", &resp, q)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn &resp, wm, nil\n}\n\n// UpsertOneTimeToken is used to create a one-time token\nfunc (a *ACLTokens) UpsertOneTimeToken(q *WriteOptions) (*OneTimeToken, *WriteMeta, error) {\n\tvar resp *OneTimeTokenUpsertResponse\n\twm, err := a.client.put(\"/v1/acl/token/onetime\", nil, &resp, q)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tif resp == nil {\n\t\treturn nil, nil, errors.New(\"no one-time token returned\")\n\t}\n\treturn resp.OneTimeToken, wm, nil\n}\n\n// ExchangeOneTimeToken is used to create a one-time token\nfunc (a *ACLTokens) ExchangeOneTimeToken(secret string, q *WriteOptions) (*ACLToken, *WriteMeta, error) {\n\tif secret == \"\" {\n\t\treturn nil, nil, errors.New(\"missing secret ID\")\n\t}\n\treq := &OneTimeTokenExchangeRequest{OneTimeSecretID: secret}\n\tvar resp *OneTimeTokenExchangeResponse\n\twm, err := a.client.put(\"/v1/acl/token/onetime/exchange\", req, &resp, q)\n\tif err != nil {\n\t\treturn nil, nil, err\n\t}\n\tif resp == nil {\n\t\treturn nil, nil, errors.New(\"no ACL token returned\")\n\t}","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/api/acl.go#L202-L238","documentation":"UpsertOneTimeToken() POSTs to /v1/acl/token/onetime to create a short-lived one-time token. If the HTTP call succeeds (no transport or API error) but the decoded response object is nil, the client treats it as an unexpected/empty server response and returns this error. It guards the dereference of resp.OneTimeToken.","triggerScenarios":"Calling ACLTokens().UppsertOneTimeToken(q) against a server that returns 200 with an empty body, or a proxy/middleware that strips the response body; response payload fails to decode into OneTimeTokenUpsertResponse leaving resp nil.","commonSituations":"Older Consul servers (pre-1.6) or non-Consul endpoints behind the same address that do not implement the one-time token endpoint; an API gateway returning an empty 200; TLS/proxy interference.","solutions":["Verify the target is a Consul server version >= 1.6 that supports one-time tokens (acl enabled).","Check any proxies/load balancers between client and server are not returning empty 200 responses.","Retry the operation; if it persists, inspect the server logs for the /v1/acl/token/onetime request."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func ottReturned(r *api.OneTimeTokenUpsertResponse) bool { return r != nil && r.OneTimeToken != nil && r.OneTimeToken.SecretID != \"\" }","tryCatchPattern":"ott, _, err := client.ACLTokens().UpsertOneTimeToken(nil)\nif err != nil {\n    if err.Error() == \"no one-time token returned\" {\n        // verify server version/ACL enabled, then retry\n    }\n    return err\n}","preventionTips":["Require Consul >= 1.6 with ACLs enabled before using one-time tokens.","Avoid proxies/gateways that may strip or buffer response bodies on this endpoint."],"tags":["consul","acl","empty-response","one-time-token"],"backgroundTag":"empty-server-response","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"}