Summary
A code --update run (codebase documentation) crashed uncaught with:
Error: Gmail refresh token is required for OAuth refresh.
at Object.process (…/langchain/dist/agents/transformers/tool-call.js:152:29)
at Object.process (…/langchain/dist/agents/transformers/subagent.js:171:22)
at StreamMux.push (…/@langchain/langgraph/dist/stream/mux.js:173:66)
at pump (…/@langchain/langgraph/dist/stream/mux.js:321:36)
Node.js v22.23.1
The run had executed for ~1h43m (Opus 4.8 on Vertex, --recursive over a large monorepo) and produced zero output before dying.
Environment
- Tag run in CI:
mediwareinc/openwiki v0.1.1-vertex.1 (the ppsplus-bradh fork on main / 0.2.x has the same structure; line refs below are from main).
- Provider:
OPENWIKI_PROVIDER=gemini-enterprise (Claude on Vertex), model claude-opus-4-8, GOOGLE_CLOUD_LOCATION=global.
- Command:
node dist/cli.js code --update --recursive --print, GitHub Actions ubuntu-latest, Node 22.
- No connector credentials configured (no
google/Gmail OAuth env vars) — this is a pure codebase-doc run.
Root cause (traced through the source)
Two distinct defects combine:
A. Connector ingest tools are exposed to the doc agent unconditionally — no mode gating
src/agent/index.ts:250 passes tools: createOpenWikiConnectorTools() to the agent regardless of run mode. There is no code-vs-connector filtering (grepping index.ts for createOpenWikiConnectorTools shows only the import and this single unconditional call site).
createOpenWikiConnectorTools() (src/connectors/tools.ts) registers openwiki_ingest_connector (and openwiki_ingest_all_connectors) whose connectorId enum includes google, slack, x, notion, etc.
So in code mode — which should only be reading the repo from git and writing openwiki/*.md — the model is handed Gmail/Slack/X ingestion tools. Under --recursive the subagent machinery fans out across subtrees, and a subagent called openwiki_ingest_connector({connectorId:"google"}) (visible in the stack: subagent.js → tool-call.js). A codebase-documentation agent has no business ingesting Gmail; these tools shouldn't be in its toolset in code mode.
B. A single-connector ingest failure isn't isolated — it propagates uncaught and kills the process
The call chain on invocation:
openwiki_ingest_connector tool func → ingestConnector() (src/connectors/tools.ts:245) →
return registry[connectorId].ingest(options); // no try/catch
→ Gmail connector ingest() (src/connectors/sources/gmail.ts:122) → getOAuthAccessToken("gmail") → token missing/expired → refreshOAuthAccessToken("gmail") (src/auth/tokens.ts:50) → refreshToken undefined →
throw new Error(`${provider.displayName} refresh token is required for OAuth refresh.`); // tokens.ts:67
Neither ingestConnector nor the tool func wraps this in try/catch, so the throw escapes the langchain tool call, rejectOutput(new Error(...)) fires, and it goes uncaught through the langgraph stream pump — terminating the whole run. (Note: ingestAllConnectors() does catch per-connector, ~tools.ts:312/338; the single-connector ingestConnector path does not — so the granular tool is the fragile one.)
Also relevant: isGmailEnabled() (gmail.ts:326) returns config.enabled !== false, i.e. defaults to enabled, and getOAuthAccessToken is only reached after that guard — so a default/near-empty google config still proceeds to the OAuth path and throws in a credential-less CI environment.
Suggested fixes
- Gate connector tools by mode. Don't include
openwiki_ingest_connector / openwiki_ingest_all_connectors / MCP connector tools in the code (codebase-doc) toolset. code mode documents a git repo and shouldn't reach external connectors at all. (Alternatively, an allowlist of tools per mode.)
- Isolate connector-ingest failures. Wrap
registry[connectorId].ingest(options) in ingestConnector (and/or the tool func) in try/catch and return a structured error result (like ingestAllConnectors already does per-connector), so a missing credential yields a recoverable tool error the agent can skip — never a process-killing uncaught throw.
- Fail fast, not after 1h43m. Whatever the toolset, a missing-credential/uncaught error inside a tool call shouldn't be able to discard an entire long, expensive model run. Consider surfacing tool errors back to the agent as tool output rather than rejecting the stream.
Fix #1 addresses the "why is this even happening in code mode" question; #2 is the defensive backstop; #3 protects the run economics.
Impact / current workaround
The crash blocked all scheduled doc generation and burned a full ~1h43m Vertex run per attempt. Workaround applied downstream: dropped --recursive from code --update (mediwareinc/Meridian.IMR#1753) so the single-pass run is far less likely to trigger a subagent connector call. That's a mitigation, not a fix — plain code --update can still call these tools since they remain in the toolset.
Repro
- Build the fork; ensure
mermaid+jsdom are installed (unrelated to this crash, but matches the run).
- Run
code --update --recursive with a Vertex/gemini-enterprise provider and no connector credentials.
- If a (sub)agent calls
openwiki_ingest_connector({connectorId:"google"}), the run dies uncaught with the Gmail refresh-token error.
Failing run: mediwareinc/Meridian.IMR Actions run 29976519621, step "Run openwiki --update".
Summary
A
code --updaterun (codebase documentation) crashed uncaught with:The run had executed for ~1h43m (Opus 4.8 on Vertex,
--recursiveover a large monorepo) and produced zero output before dying.Environment
mediwareinc/openwikiv0.1.1-vertex.1(theppsplus-bradhfork onmain/ 0.2.x has the same structure; line refs below are frommain).OPENWIKI_PROVIDER=gemini-enterprise(Claude on Vertex), modelclaude-opus-4-8,GOOGLE_CLOUD_LOCATION=global.node dist/cli.js code --update --recursive --print, GitHub Actionsubuntu-latest, Node 22.google/Gmail OAuth env vars) — this is a pure codebase-doc run.Root cause (traced through the source)
Two distinct defects combine:
A. Connector ingest tools are exposed to the doc agent unconditionally — no mode gating
src/agent/index.ts:250passestools: createOpenWikiConnectorTools()to the agent regardless of run mode. There is nocode-vs-connector filtering (greppingindex.tsforcreateOpenWikiConnectorToolsshows only the import and this single unconditional call site).createOpenWikiConnectorTools()(src/connectors/tools.ts) registersopenwiki_ingest_connector(andopenwiki_ingest_all_connectors) whoseconnectorIdenum includesgoogle,slack,x,notion, etc.So in
codemode — which should only be reading the repo from git and writingopenwiki/*.md— the model is handed Gmail/Slack/X ingestion tools. Under--recursivethe subagent machinery fans out across subtrees, and a subagent calledopenwiki_ingest_connector({connectorId:"google"})(visible in the stack:subagent.js→tool-call.js). A codebase-documentation agent has no business ingesting Gmail; these tools shouldn't be in its toolset incodemode.B. A single-connector ingest failure isn't isolated — it propagates uncaught and kills the process
The call chain on invocation:
openwiki_ingest_connectortoolfunc→ingestConnector()(src/connectors/tools.ts:245) →→ Gmail connector
ingest()(src/connectors/sources/gmail.ts:122) →getOAuthAccessToken("gmail")→ token missing/expired →refreshOAuthAccessToken("gmail")(src/auth/tokens.ts:50) →refreshTokenundefined →Neither
ingestConnectornor the toolfuncwraps this in try/catch, so the throw escapes the langchain tool call,rejectOutput(new Error(...))fires, and it goes uncaught through the langgraph streampump— terminating the whole run. (Note:ingestAllConnectors()does catch per-connector, ~tools.ts:312/338; the single-connectoringestConnectorpath does not — so the granular tool is the fragile one.)Also relevant:
isGmailEnabled()(gmail.ts:326) returnsconfig.enabled !== false, i.e. defaults to enabled, andgetOAuthAccessTokenis only reached after that guard — so a default/near-empty google config still proceeds to the OAuth path and throws in a credential-less CI environment.Suggested fixes
openwiki_ingest_connector/openwiki_ingest_all_connectors/ MCP connector tools in thecode(codebase-doc) toolset.codemode documents a git repo and shouldn't reach external connectors at all. (Alternatively, an allowlist of tools per mode.)registry[connectorId].ingest(options)iningestConnector(and/or the toolfunc) in try/catch and return a structured error result (likeingestAllConnectorsalready does per-connector), so a missing credential yields a recoverable tool error the agent can skip — never a process-killing uncaught throw.Fix #1 addresses the "why is this even happening in code mode" question; #2 is the defensive backstop; #3 protects the run economics.
Impact / current workaround
The crash blocked all scheduled doc generation and burned a full ~1h43m Vertex run per attempt. Workaround applied downstream: dropped
--recursivefromcode --update(mediwareinc/Meridian.IMR#1753) so the single-pass run is far less likely to trigger a subagent connector call. That's a mitigation, not a fix — plaincode --updatecan still call these tools since they remain in the toolset.Repro
mermaid+jsdomare installed (unrelated to this crash, but matches the run).code --update --recursivewith a Vertex/gemini-enterpriseprovider and no connector credentials.openwiki_ingest_connector({connectorId:"google"}), the run dies uncaught with the Gmail refresh-token error.Failing run: mediwareinc/Meridian.IMR Actions run 29976519621, step "Run openwiki --update".