Skip to content

feat(error-tracking): capture in existing boundaries, version-aware server hooks, server identity - #446

Draft
ablaszkiewicz wants to merge 1 commit into
mainfrom
mfga/nextjs-capture
Draft

ablaszkiewicz wants to merge 1 commit into
mainfrom
mfga/nextjs-capture

Conversation

@ablaszkiewicz

@ablaszkiewicz ablaszkiewicz commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Pull requests: 1. PostHog/posthog-js#5472 2. PostHog/posthog-js#5473 3. 👉 this PR 4. PostHog/wizard-workbench#4805 5. PostHog/posthog#125314

Problem

wizard error-tracking on four Next.js workbench apps (16 App Router, the same app with PostHog already present, 14 App Router, 15 Pages Router):

  • Existing boundaries left bare. It left the app's existing error.tsx without capture in 3 of 4 App Router runs, so every render error under it was lost. The step skill told the agent not to wrap individual routes, and the agent read that as leaving existing boundaries alone.
  • A dead hook on Next.js 14. It exported an onRequestError that Next.js 14 never calls, and the report told the user server errors were covered. All 10 server error scenarios were lost.
  • Unlinked server errors. No server exception carried the browser's session. Requests identified by tracing headers went to a random person, and the browser init never set tracing_headers.
  • Late autocapture. It built the posthog-node client on the first request error, so its process-level autocapture started late.

Changes

context/agents/error-tracking/capture-exceptions.md:

  • The boundaries an app already has (each Next.js error.tsx, a custom global-error.tsx, a Pages Router _error or _app boundary) are framework hooks: add capture to every one. Creating new per-route boundaries is still the hand-wrapping to avoid.
  • Read the installed framework version before wiring a hook. Next.js 14 never calls onRequestError and runs instrumentation.ts only with experimental.instrumentationHook. Where the version has no hook, name the uncaptured errors and the upgrade in the handoff.
  • Create the server client when the server starts (register() in Next.js).
  • A new section, "Name the user on server errors": tracing_headers in the browser init, and on the server the X-POSTHOG-* headers first, then the PostHog cookie with a fresh session, never used for authentication.

context/skills/integration-v2/error-tracking-step/description.md: existing boundaries swallow what they catch, so capture goes in each of them.

Test plan

  • npm test (220 passing)
  • wizard error-tracking with this branch (--local-context-mill) on the four workbench apps, with the onboarding docs change seeded into the docs cache. Every run completed. Each production build was then exercised in a browser and over HTTP, and every event was checked in PostHog:
    • the existing error.tsx was captured in all three App Router apps
    • the Next.js 14 run exported no onRequestError, and its report names the server gap and the upgrade
    • on Next.js 16 and 15 Pages, every request scenario was linked to the browser user and session

Passing scenarios, before → after (flow and docs together): 16 App 6 → 13 of 15, 16 App with PostHog 5 → 13 of 15, 14 App 4 → 5 of 14, 15 Pages 5 → 10 of 11. The rest wait on the SDK PRs, a Next.js proxy bug, or edge source maps on Turbopack.

Still open: on Next.js 14 the agent leaves experimental.instrumentationHook as a follow-up for the user. The capture task may not touch build config while the configure task owns next.config.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FkuJAD3n8f6Ra7L9p2UmPw

…erver hooks, server identity

The capture task now adds capture to every error boundary the app already
has (each Next.js error.tsx, a custom global-error.tsx, a Pages Router
_error or _app boundary), checks the installed framework version before
wiring a hook that version may not have (Next.js 14 has no onRequestError),
starts the server client at boot, and links server errors to the browser
user through tracing headers and the PostHog cookie.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FkuJAD3n8f6Ra7L9p2UmPw
@github-actions

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 feature-flags
  • /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/google-adk
  • /wizard-ci ai-observability/groq
Show more apps
  • /wizard-ci ai-observability/manual-capture
  • /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 feature-flags/django
  • /wizard-ci feature-flags/next-js
  • /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 wizard branch:

  • /wizard-ci all wizard:my-branch

Add wizard:<branch> to any command above to pin the wizard branch. It defaults to main.

Results will be posted here when complete.

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.

1 participant