fix(infra): wrap provider auth resolution in timeout for status --usage --json#74185
fix(infra): wrap provider auth resolution in timeout for status --usage --json#74185yelog wants to merge 9 commits into
Conversation
Greptile SummaryWraps Confidence Score: 4/5Safe to merge — the change is small, consistent with the existing timeout pattern, and the new test covers the regression path. No P0 or P1 findings. Two P2 style suggestions (complex type in test, missing log on timeout). Score stays at 4/5. No files require special attention. Prompt To Fix All With AIThis is a comment left during a code review.
Path: src/infra/provider-usage.load.test.ts
Line: 176-181
Comment:
**Overly complex config type extraction**
The conditional type chain here resolves to `OpenClawConfig`, which is already exported from `../config/config.js` (the same import used in the source file). Importing it directly is cleaner and easier to understand.
```suggestion
config: {} as import("../config/config.js").OpenClawConfig,
```
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: src/infra/provider-usage.load.ts
Line: 94-105
Comment:
**No signal on auth timeout**
`withTimeout` silently returns `[]` when auth resolution exceeds `timeoutMs`. At the call site there's no observable difference between "no providers configured" and "auth timed out", which makes this hard to diagnose in the field. Consider emitting a debug/warning log before returning the fallback so operators can distinguish the two cases.
How can I resolve this? If you propose a fix, please make it concise.Reviews (1): Last reviewed commit: "fix(infra): wrap provider auth resolutio..." | Re-trigger Greptile |
| config: {} as Parameters<typeof loadProviderUsageSummary>[0] extends infer O | ||
| ? O extends { config?: infer C } | ||
| ? NonNullable<C> | ||
| : never | ||
| : never, | ||
| env: {}, |
There was a problem hiding this comment.
Overly complex config type extraction
The conditional type chain here resolves to OpenClawConfig, which is already exported from ../config/config.js (the same import used in the source file). Importing it directly is cleaner and easier to understand.
| config: {} as Parameters<typeof loadProviderUsageSummary>[0] extends infer O | |
| ? O extends { config?: infer C } | |
| ? NonNullable<C> | |
| : never | |
| : never, | |
| env: {}, | |
| config: {} as import("../config/config.js").OpenClawConfig, |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/provider-usage.load.test.ts
Line: 176-181
Comment:
**Overly complex config type extraction**
The conditional type chain here resolves to `OpenClawConfig`, which is already exported from `../config/config.js` (the same import used in the source file). Importing it directly is cleaner and easier to understand.
```suggestion
config: {} as import("../config/config.js").OpenClawConfig,
```
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| const auths = await withTimeout( | ||
| resolveProviderAuths({ | ||
| providers: opts.providers ?? usageProviders, | ||
| auth: opts.auth, | ||
| agentDir: opts.agentDir, | ||
| config, | ||
| env, | ||
| skipPluginAuthWithoutCredentialSource: opts.skipPluginAuthWithoutCredentialSource, | ||
| }), | ||
| timeoutMs, | ||
| [], | ||
| ); |
There was a problem hiding this comment.
withTimeout silently returns [] when auth resolution exceeds timeoutMs. At the call site there's no observable difference between "no providers configured" and "auth timed out", which makes this hard to diagnose in the field. Consider emitting a debug/warning log before returning the fallback so operators can distinguish the two cases.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/infra/provider-usage.load.ts
Line: 94-105
Comment:
**No signal on auth timeout**
`withTimeout` silently returns `[]` when auth resolution exceeds `timeoutMs`. At the call site there's no observable difference between "no providers configured" and "auth timed out", which makes this hard to diagnose in the field. Consider emitting a debug/warning log before returning the fallback so operators can distinguish the two cases.
How can I resolve this? If you propose a fix, please make it concise.|
Codex review: needs changes before merge. Reviewed July 3, 2026, 4:08 PM ET / 20:08 UTC. Summary PR surface: Source +33, Tests +161. Total +194 across 6 files. Reproducibility: yes. at source level: current main awaits resolveProviderAuths before any timeout boundary, and the linked report gives a concrete non-TTY subprocess command. I did not run the live hang reproduction in this read-only review. Review metrics: 1 noteworthy metric.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Copy recommended automerge instructionNext step before merge
Security Review findings
Review detailsBest possible solution: Land a rebased timeout-and-warning patch on current main that leaves default status auth-hook eligibility unchanged and preserves Codex synthetic plus proxy-aware usage behavior. Do we have a high-confidence way to reproduce the issue? Yes at source level: current main awaits resolveProviderAuths before any timeout boundary, and the linked report gives a concrete non-TTY subprocess command. I did not run the live hang reproduction in this read-only review. Is this the best way to solve the issue? No as currently written. The timeout boundary is the right layer, but the branch must be rebased onto current main and should not change status auth-hook eligibility without owner approval and compatibility proof. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 5361e5a0b455. Label changesLabel justifications:
Evidence reviewedPR surface: Source +33, Tests +161. Total +194 across 6 files. View PR surface stats
Acceptance criteria:
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
d619d4d to
680d2cd
Compare
889bbc8 to
9852b63
Compare
|
Rebased onto latest Validation on the rebased branch: The first formatter attempt was interrupted while pnpm retried optional binary downloads from the configured registry; retrying the same formatter command passed. Remaining merge gate: I still need to add redacted real behavior proof from a non-TTY |
|
After-fix real behavior proof from the PR branch, redacted to command status and JSON shape only. Behavior addressed: non-TTY Evidence after fix: {
"branch": "fix/status-json-usage-auth-timeout-74085",
"head": "9852b6356b6a8369bc4f9e19b71745466d6103c5",
"command": "node scripts/run-node.mjs status --usage --json",
"nonTty": true,
"exitStatus": 0,
"signal": null,
"timedOut": false,
"elapsedMs": 6513,
"stdoutBytes": 2757,
"stderrBytes": 0,
"parsedJson": true,
"topLevelKeys": [
"agents",
"channelSummary",
"gateway",
"gatewayService",
"heartbeat",
"lastHeartbeat",
"memory",
"memoryPlugin",
"nodeService",
"os",
"queuedSystemEvents",
"runtimeVersion",
"secretDiagnostics",
"sessions",
"taskAudit",
"tasks",
"update",
"updateChannel",
"updateChannelSource",
"usage"
],
"hasUsage": true,
"usageKeys": [
"providers",
"updatedAt"
],
"usageProviders": 1,
"stderrPreview": []
}Observed result after fix: The non-TTY subprocess exited successfully in about 6.5s, did not hit the 45s timeout, emitted parseable JSON on stdout, and included a top-level @clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
…ge --json resolveProviderAuths was called without any timeout boundary, so plugin auth hooks (OAuth token refresh, secret exec resolvers) could hang indefinitely in non-TTY subprocess contexts. Wrap the call in the existing withTimeout helper using the same timeoutMs budget so the status JSON command returns empty providers on auth timeout instead of hanging. Fixes openclaw#74085
7769734 to
5e0acee
Compare
|
Closing this candidate without marking #74085 fixed. It is 7,115 commits behind current main, conflicts in the status/provider-usage surface, and its timeout returns an empty fallback without cancelling the in-flight auth work. The current OpenAI request timeout does not cover arbitrary provider/auth hooks. If the problem reproduces on current OpenClaw, please open a fresh report with a current non-TTY repro; a replacement must propagate cancellation/deadline to the actual auth operation and preserve current status usage paths. |
Summary
resolveProviderAuths()in the existingwithTimeouthelper so auth resolution (OAuth token refresh, plugin auth hooks, secret exec resolvers) cannot hang indefinitelyProblem
openclaw status --usage --jsonhangs when called from a non-TTY subprocess (regression from 2026.4.23 to 2026.4.26). The individual provider usage fetches are bounded bywithTimeout, butresolveProviderAuths()— which iterates sequentially over 7 providers calling plugin auth hooks, OAuth token refresh, and secret ref resolvers — had no timeout boundary. In a non-TTY subprocess, any of these can block indefinitely.Changes
src/infra/provider-usage.load.tsresolveProviderAuths()call at line 94 inwithTimeout(…, timeoutMs, [])using the same timeout budget as the fetch phase[](empty auths) which causesloadProviderUsageSummaryto return{ providers: [] }instead of hangingsrc/infra/provider-usage.load.test.tsresolveProviderAuthsto support testing the timeout pathReal behavior proof
Behavior addressed: non-TTY
status --usage --jsonshould complete instead of hanging while provider usage auth is resolved.Real environment tested: local OpenClaw source checkout on branch
fix/status-json-usage-auth-timeout-74085, head9852b6356b6a8369bc4f9e19b71745466d6103c5.Exact steps or command run after this patch:
Evidence after fix:
{ "branch": "fix/status-json-usage-auth-timeout-74085", "head": "9852b6356b6a8369bc4f9e19b71745466d6103c5", "command": "node scripts/run-node.mjs status --usage --json", "nonTty": true, "exitStatus": 0, "signal": null, "timedOut": false, "elapsedMs": 6513, "stdoutBytes": 2757, "stderrBytes": 0, "parsedJson": true, "topLevelKeys": [ "agents", "channelSummary", "gateway", "gatewayService", "heartbeat", "lastHeartbeat", "memory", "memoryPlugin", "nodeService", "os", "queuedSystemEvents", "runtimeVersion", "secretDiagnostics", "sessions", "taskAudit", "tasks", "update", "updateChannel", "updateChannelSource", "usage" ], "hasUsage": true, "usageKeys": [ "providers", "updatedAt" ], "usageProviders": 1, "stderrPreview": [] }Observed result after fix: The non-TTY subprocess exited successfully in about 6.5s, did not hit the 45s timeout, emitted parseable JSON on stdout, and included a top-level
usageobject with provider usage data.What was not tested: This was a local source checkout proof rather than a packaged install, and it does not print provider names, auth profiles, credentials, or raw usage values.
Fixes #74085