Skip to content

code mode exposes connector ingest tools + a single-connector ingest failure crashes the whole run (Gmail OAuth) #4

Description

@ppsplus-bradh

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.jstool-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 funcingestConnector() (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 pumpterminating 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

  1. 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.)
  2. 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.
  3. 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

  1. Build the fork; ensure mermaid+jsdom are installed (unrelated to this crash, but matches the run).
  2. Run code --update --recursive with a Vertex/gemini-enterprise provider and no connector credentials.
  3. 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".

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions