{"record":{"id":"386f46a482b0083d","repo":"chenhg5/cc-connect","slug":"auth-json-missing-tokens-account-id","errorCode":null,"errorMessage":"auth.json missing tokens.account_id","messagePattern":"auth\\.json missing tokens\\.account_id","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/codex/usage.go","lineNumber":84,"sourceCode":"\tdata, err := readFile(path)\n\tif err != nil {\n\t\treturn codexOAuthTokens{}, fmt.Errorf(\"read %s: %w\", path, err)\n\t}\n\n\tvar payload struct {\n\t\tTokens struct {\n\t\t\tAccessToken string `json:\"access_token\"`\n\t\t\tAccountID   string `json:\"account_id\"`\n\t\t} `json:\"tokens\"`\n\t}\n\tif err := json.Unmarshal(data, &payload); err != nil {\n\t\treturn codexOAuthTokens{}, fmt.Errorf(\"parse auth.json: %w\", err)\n\t}\n\tif strings.TrimSpace(payload.Tokens.AccessToken) == \"\" {\n\t\treturn codexOAuthTokens{}, fmt.Errorf(\"auth.json missing tokens.access_token\")\n\t}\n\tif strings.TrimSpace(payload.Tokens.AccountID) == \"\" {\n\t\treturn codexOAuthTokens{}, fmt.Errorf(\"auth.json missing tokens.account_id\")\n\t}\n\n\treturn codexOAuthTokens{\n\t\tAccessToken: payload.Tokens.AccessToken,\n\t\tAccountID:   payload.Tokens.AccountID,\n\t}, nil\n}\n\nfunc (a *Agent) fetchUsage(ctx context.Context, client *http.Client, tokens codexOAuthTokens) (*core.UsageReport, error) {\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, codexUsageURL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+tokens.AccessToken)\n\treq.Header.Set(\"ChatGPT-Account-Id\", tokens.AccountID)\n\treq.Header.Set(\"User-Agent\", \"codex-cli\")\n\n\tresp, err := client.Do(req)","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/agent/codex/usage.go#L66-L102","documentation":"readOAuthTokens requires a non-empty tokens.account_id in auth.json; this error is thrown when the JSON parses but account_id is missing, empty, or whitespace-only. The account id is sent as the ChatGPT-Account-Id header on usage requests, so without it the library cannot query the correct account and fails before making the request.","triggerScenarios":"json.Unmarshal succeeds but strings.TrimSpace(payload.Tokens.AccountID) == \"\" — auth.json tokens object lacks account_id. Detected by TestReadOAuthTokens_MissingFields and surfaced through GetUsage.","commonSituations":"Personal-only ChatGPT logins or older Codex CLI versions whose auth.json did not include account_id; hand-assembled auth.json missing the field; schema drift after a Codex CLI upgrade/downgrade; a partially written tokens object.","solutions":["Re-run `codex login` with a current Codex CLI so account_id is populated","Inspect auth.json: confirm tokens.account_id exists and is non-empty","Upgrade (or match) the Codex CLI version used to create auth.json to one that writes account_id","If hand-copying credentials, include the complete tokens object"],"exampleFix":"// before\n// assumes account_id present\nusage, err := agent.GetUsage(ctx)\n// after: pre-check\nvar a struct{ Tokens struct{ AccountID string `json:\"account_id\"` } `json:\"tokens\"` }\nif json.Unmarshal(authBytes, &a) == nil && strings.TrimSpace(a.Tokens.AccountID) == \"\" {\n    log.Fatal(\"auth.json lacks tokens.account_id; re-run `codex login` with latest codex CLI\")\n}\nusage, err := agent.GetUsage(ctx)","handlingStrategy":"validation","validationCode":"var a struct{ Tokens struct{ AccountID string `json:\"account_id\"` } `json:\"tokens\"` }\njson.Unmarshal(b, &a)\nif strings.TrimSpace(a.Tokens.AccountID) == \"\" { return errors.New(\"missing tokens.account_id; re-run `codex login`\") }","typeGuard":null,"tryCatchPattern":"if _, err := agent.GetUsage(ctx); err != nil && strings.Contains(err.Error(), \"missing tokens.account_id\") {\n    log.Println(\"Codex auth.json predates account_id — update codex CLI and re-login\")\n}","preventionTips":["Keep the Codex CLI current so auth.json includes account_id","Never hand-craft auth.json; use `codex login` output","Diff auth.json against a known-good login when in doubt","Include account_id checks in preflight config validation"],"tags":["go","codex","oauth","validation"],"backgroundTag":"empty-required-field","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}