Skip to content

fix(agent): tell users to clear a broken npx cache instead of "API Error" - #1200

Draft
posthog[bot] wants to merge 7 commits into
mainfrom
posthog-self-driving/fixagent-stop-filing-broken-npx-ba5349
Draft

fix(agent): tell users to clear a broken npx cache instead of "API Error"#1200
posthog[bot] wants to merge 7 commits into
mainfrom
posthog-self-driving/fixagent-stop-filing-broken-npx-ba5349

Conversation

@posthog

@posthog posthog Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Problem

  • A user with a half-written npx download is told the wizard hit an "API Error" and asked to email support, when the real cause is a corrupt install they can fix in one command.
  • ~/.npm/_npx extractions can truncate. Node then fails the pi-coding-agent dynamic import with ERR_MODULE_NOT_FOUND, and both pi catch blocks fall through to AgentErrorType.API_ERROR.
  • Low volume, but every occurrence either costs a support round trip or ends the install. The same shape appears in wizard: agent api error telemetry from a second user on Windows.

Changes

Before After
Any non-rate-limit throw → API_ERRORPHW_AGENT_API_ERROR A module resolution failure → MODULE_MISSINGPHW_AGENT_MODULE_MISSING
"API Error … Please report this to: wizard@posthog.com" The exact cached directory to delete, plus the rerun command
Filed under the same analytics bucket as gateway timeouts and 429s Own bucket: agent module missing
  • isModuleNotFoundError reads the Node error code and falls back to the message text, because a rethrow across a boundary keeps the text but drops the code.
  • formatModuleMissingMessage takes the .../_npx/<hash>/... path out of the failure text, so the user deletes one download and not the whole cache. It falls back to the platform npx cache root, and prints rm -rf or Remove-Item per platform.
  • Both pi catch blocks get the branch: harness/pi/index.ts (default flow) and harness/pi/task.ts (orchestrator tasks).
New message
Broken npx download

The wizard could not load one of its own dependencies. The npx cache holds
an incomplete copy of it. Nothing is wrong with your project.

Delete the cached download, then run the wizard again:

  rm -rf "/Users/a/.npm/_npx/9f2"
  npx @posthog/wizard@latest

Details: Cannot find package '/Users/a/.npm/_npx/9f2/node_modules/chalk/index.js'

Still stuck? Email wizard@posthog.com and we will help.

Test plan

  • pnpm build && pnpm test && pnpm lint — 2606 tests pass, 0 lint errors.
  • New unit tests in src/lib/errors/__tests__/module-missing.test.ts cover: the Node error code, the message-only form, an ordinary API failure staying unclassified, the exact directory in the output, and the cache-root fallback.
  • Not reproduced end to end. Corrupting a real npx cache to trigger the import failure was out of scope for this change.

LLM context

Written by PostHog Desktop from the linked inbox report. Considered and skipped: the same classification in agent-interface.ts (the Claude SDK harness). A module failure there rethrows and never reaches the "API Error" screen, so it is a different symptom.


Created with PostHog Desktop from this inbox report.

…ror"

A half-written ~/.npm/_npx extraction makes Node fail the pi-coding-agent dynamic import with ERR_MODULE_NOT_FOUND. Both pi catch blocks classified that as AgentErrorType.API_ERROR, so the user saw an "API Error" heading and a request to email support, for a problem they can fix in one command.

Add AgentErrorType.MODULE_MISSING (PHW_AGENT_MODULE_MISSING), detect the Node error in the run and task catch blocks, and render a message that names the exact cached download to delete and the command to rerun.

Generated-By: PostHog Desktop
Task-Id: 9fe44d3a-6a47-4d1d-8950-c84b7281c08b
@posthog

posthog Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

🦔 PostHog Review reviewed this pull request

Found 1 must fix, 2 should fix, 3 consider.

Published 6 findings (view the review).

Resolved comments: 2 fixed, 1 already settled

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

🧙 Wizard CI

Run the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands:

Test all apps:

  • /wizard-ci all

Test all apps in a directory:

  • /wizard-ci ai-observability
  • /wizard-ci basic-integration
  • /wizard-ci mcp-analytics
  • /wizard-ci replay-vision
  • /wizard-ci revenue
  • /wizard-ci self-driving
  • /wizard-ci warehouse
  • /wizard-ci warehouse-seeded

Test an individual app:

  • /wizard-ci ai-observability/anthropic
  • /wizard-ci ai-observability/groq
  • /wizard-ci ai-observability/manual-capture
Show more apps
  • /wizard-ci ai-observability/openai
  • /wizard-ci ai-observability/openai-agents
  • /wizard-ci ai-observability/opentelemetry
  • /wizard-ci ai-observability/vercel-ai
  • /wizard-ci basic-integration/android
  • /wizard-ci basic-integration/angular
  • /wizard-ci basic-integration/astro
  • /wizard-ci basic-integration/django
  • /wizard-ci basic-integration/fastapi
  • /wizard-ci basic-integration/flask
  • /wizard-ci basic-integration/flutter
  • /wizard-ci basic-integration/javascript-node
  • /wizard-ci basic-integration/javascript-web
  • /wizard-ci basic-integration/laravel
  • /wizard-ci basic-integration/next-js
  • /wizard-ci basic-integration/nuxt
  • /wizard-ci basic-integration/python
  • /wizard-ci basic-integration/rails
  • /wizard-ci basic-integration/react-native
  • /wizard-ci basic-integration/react-router
  • /wizard-ci basic-integration/sveltekit
  • /wizard-ci basic-integration/swift
  • /wizard-ci basic-integration/tanstack-router
  • /wizard-ci basic-integration/tanstack-start
  • /wizard-ci basic-integration/vue
  • /wizard-ci mcp-analytics/custom-dispatcher
  • /wizard-ci mcp-analytics/typescript-sdk
  • /wizard-ci replay-vision/javascript-node
  • /wizard-ci replay-vision/next-js
  • /wizard-ci replay-vision/react-vite
  • /wizard-ci revenue/stripe
  • /wizard-ci self-driving/astro
  • /wizard-ci self-driving/fastapi
  • /wizard-ci self-driving/nuxt
  • /wizard-ci self-driving/react-router
  • /wizard-ci self-driving/sveltekit
  • /wizard-ci warehouse/monorepo-env
  • /wizard-ci warehouse/multi-source-next
  • /wizard-ci warehouse/stripe-node
  • /wizard-ci warehouse/zero-source
  • /wizard-ci warehouse-seeded/next-stripe
  • /wizard-ci warehouse-seeded/next-stripe-declined

Test against a Context Mill branch:

  • /wizard-ci all context-mill:my-branch

Add context-mill:<branch> to any command above to pin the Context Mill branch. It defaults to main.

Results will be posted here when complete.

@posthog

posthog Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

PostHog Review alpha 🦔 If you find any issues helpful - please reply "valid", "invalid", etc., for evaluation purposes 🙏

@posthog posthog Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PostHog Review

Found 1 must fix, 2 should fix, 3 consider.

Comment thread src/lib/errors/codes.ts
Comment thread src/lib/agent/runner/harness/pi/index.ts
Comment thread src/lib/errors/module-missing.ts Outdated
Comment thread src/lib/agent/runner/harness/pi/task.ts
Comment thread src/lib/errors/module-missing.ts
Comment thread src/lib/errors/module-missing.ts Outdated
posthog Bot added 6 commits September 3, 2026 11:58
The catalog doc's "Extending the catalog" procedure requires a table row for
every new code. PHW_AGENT_MODULE_MISSING had the codes.ts constant and the
ERROR_CATALOG entry but no documented row, so an integrator reading the
markdown mirror would fall back to a default retry policy on a failure that
never heals between runs.

Generated-By: PostHog Desktop
Task-Id: 4c97b145-3d33-4a0c-b890-f58cb5ef8189
… test

The rate-limit branch matches "429" anywhere in the lowercased message. An npx
cache directory is a 16-character hex hash, and Node's ERR_MODULE_NOT_FOUND
message embeds that path twice, so a hash containing "429" made a broken npx
download report as a rate limit — and from there as the same "API Error" text
this change set out to replace.

Module resolution is decided by the error object itself, so it now goes first
in both pi catch blocks. A genuine rate-limit message never satisfies
isModuleNotFoundError, so no other input changes classification.

The loose "429" substring test is pre-existing and left as is; tightening it to
a status token is a separate change to rate-limit handling.

Generated-By: PostHog Desktop
Task-Id: 4c97b145-3d33-4a0c-b890-f58cb5ef8189
Every non-orchestrator program renders this message through linear.ts, not just
the default integration flow. The literal `npx @posthog/wizard@latest` line sat
directly under a "run the wizard again" instruction, so a user who ran a
read-only command such as `wizard audit events` would copy-paste their way into
the base integration flow, which changes their project.

The message now asks the user to run the same wizard command again, which is
correct for every command and for an explicit --install-dir. Rebuilding the
real invocation from argv was rejected: it would have to filter secret option
values such as --api-key for no gain over prose.

Generated-By: PostHog Desktop
Task-Id: 4c97b145-3d33-4a0c-b890-f58cb5ef8189
… screen

runPiTask classified a broken npx download, but nothing read the result: the
executor's RunTask returns void and the drain call discarded it, while the seed
path only logged. Orchestrator runs — the default integration flow and metrics
— therefore still ended on the generic "report this to us" text, which is the
population this change was written for.

Both paths now record the failure, and a run that ended badly aborts with
PHW_AGENT_MODULE_MISSING and the cache repair command before the queue verdict
is read. The abort is gated on the run having actually failed, so a run that
completed in spite of one bad task keeps its result.

Reusing one AgentResult router across the linear and orchestrator sequences was
rejected here: the two abort on different verdicts, and the shared abstraction
is a larger design change than this fix needs.

Generated-By: PostHog Desktop
Task-Id: 4c97b145-3d33-4a0c-b890-f58cb5ef8189
The prefix before `_npx` excluded whitespace, so a home directory with a space
in it started the match after the last space: `/Users/First Last/.npm/_npx/9f2`
was captured as `Last/.npm/_npx/9f2`. The printed repair then targeted a
relative path — on POSIX `rm -rf` matches nothing and exits 0, so the user
believes the cache is clear, reruns, and hits the identical failure. Windows,
where `C:\Users\John Smith` is ordinary, fails loudly instead.

The prefix is now fenced by the quotes Node puts around a specifier rather than
by whitespace, and has to start at a real root (`/`, a drive, or a UNC share).
A fragment that cannot be rooted no longer matches at all, so it reaches the
whole-cache fallback instead of being printed as if it were verified — half a
path is worse than none here. The trailing segment stops at whitespace too, so
prose after the hash is no longer swallowed.

Covered by three tests: a POSIX path with a space, a Windows path with a space,
and an unrooted fragment falling back.

Generated-By: PostHog Desktop
Task-Id: 398deef2-51b6-41a3-9b19-10e368612efe
`process.platform` names the OS, not the shell. `Remove-Item` is a PowerShell
cmdlet, so a Windows user at a Command Prompt who pastes the printed line gets
"'Remove-Item' is not recognized" — the recovery step fails even when the path
is right, which is the one thing this message exists to prevent.

Windows now prints both forms, labelled and aligned, and the user picks the one
their prompt understands:

  PowerShell:      Remove-Item -Recurse -Force "C:\...\_npx\abc"
  Command Prompt:  rmdir /s /q "C:\...\_npx\abc"

Detecting the shell was rejected: the repo carries no shell detection today
(every other process.platform check picks a filesystem location, where the OS is
the right axis), and inferring it from ComSpec or MSYSTEM is a new concern for
no gain over letting the reader choose a labelled line.

Non-Windows output is byte-identical. Covered by a test that stubs
process.platform to win32, matching the pattern in the MCP client tests.

Generated-By: PostHog Desktop
Task-Id: 398deef2-51b6-41a3-9b19-10e368612efe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants