[GH-ISSUE #2538] fix(inspector): report fatal protocol errors during the observation window #854

Closed
opened 2026-10-15 18:29:01 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coygeek on GitHub (Oct 13, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2538

Summary

A V8 Inspector observation reports success when its socket receives a fatal malformed message after the enable commands finish. It keeps earlier script metadata, silently loses later valid events and reports no protocol failure. The result therefore hides an interrupted capture from the caller.

Steps to reproduce

  1. Serve a disposable Inspector fixture on loopback port 9230. /json/version returns { "Browser": "node.js/v24.4.1", "Protocol-Version": "1.3" }. /json/list returns one row with id: "target", type: "node", url: "https://example.test/app.js", attached: false and webSocketDebuggerUrl: "ws://127.0.0.1:9230/target". Accept a WebSocket at /target and keep it open.
  2. Reply to Runtime.enable with a Runtime.executionContextCreated event whose context is { "id": 1, "name": "main", "origin": "" }, followed by { "id": <command id>, "result": {} }. Reply to Debugger.enable with the first event below followed by the same successful reply shape.
{ "method": "Debugger.scriptParsed", "params": { "scriptId": "1", "url": "node:fs", "executionContextId": 1, "hash": "h", "length": 3, "isModule": false } }
  1. Thirty milliseconds after sending the second enable reply, send { "bogus": true }, followed by another well-formed Debugger.scriptParsed event with scriptId: "2", url: "node:path", executionContextId: 1, hash: "later", length: 4 and isModule: false.
  2. Call new V8InspectorProvider().observe({ inspector_endpoint: "http://127.0.0.1:9230", target_id: "target", observation_ms: 250 }) in a focused integration test. Compare with a control that sends the identical sequence except for the malformed message.

Expected behavior

A fatal protocol parsing error inside the active observation window returns protocol_error, with the previously collected script and context metadata retained as a partial observation. An otherwise identical session containing only valid frames finishes successfully and retains both script events.

Actual behavior

The malformed-message run returned ok: true, one script, two observed events, zero dropped events and truncated: false. The later valid script event was absent. The control returned success with both scripts and three events. Each fixture was run once; the assertion requiring an error for the malformed-message fixture failed.

Evidence

  • Expected source: src/browser/CdpConnection.ts:106 defines fatal parsing failure notification even without pending commands, and src/browser/execution/CdpExecutionCollection.ts:46 propagates that failure during browser capture. AGENTS.md requires preserving partial facts and meaningful failure reasons; src/inspector/V8InspectorProvider.ts:199 already preserves partial observations for typed capture failures.
  • Failure source: src/inspector/V8InspectorProvider.ts:512 waits for the duration or disconnect only. src/browser/CdpConnection.ts:227 treats the supplied message as a fatal invalid envelope, suppresses subsequent events and leaves the socket open. The focused loopback fixture returned the successful result recorded above.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Restoration check

Run the delayed malformed-message fixture after both enable replies and receive protocol_error with the first script and execution context preserved as a partial observation. Run the all-valid control and retain both scripts in a successful observation. Keep the malformed frame out of the command-reply interval so a pending command rejection cannot mask the idle-window failure.

Runtime or environment

Source baseline 8b181716ac. Node v26.10.0, npm 11.19.1 and lockfile-installed dependencies. The focused test used a local HTTP/WebSocket fixture; no live runtime target was observed.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A bounded protocol failure makes an interrupted observation appear successful and suppresses later script metadata. The fixture directly demonstrated the loss; real-endpoint frequency is unknown.
  • Workaround status: none
  • Workaround basis: The result contains no protocol error or truncation signal, so a caller cannot reliably identify this interruption from the returned observation or select a request option that detects it.
Originally created by @coygeek on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2538 ## Summary A V8 Inspector observation reports success when its socket receives a fatal malformed message after the enable commands finish. It keeps earlier script metadata, silently loses later valid events and reports no protocol failure. The result therefore hides an interrupted capture from the caller. ## Steps to reproduce 1. Serve a disposable Inspector fixture on loopback port 9230. `/json/version` returns `{ "Browser": "node.js/v24.4.1", "Protocol-Version": "1.3" }`. `/json/list` returns one row with `id: "target"`, `type: "node"`, `url: "https://example.test/app.js"`, `attached: false` and `webSocketDebuggerUrl: "ws://127.0.0.1:9230/target"`. Accept a WebSocket at `/target` and keep it open. 2. Reply to `Runtime.enable` with a `Runtime.executionContextCreated` event whose context is `{ "id": 1, "name": "main", "origin": "" }`, followed by `{ "id": <command id>, "result": {} }`. Reply to `Debugger.enable` with the first event below followed by the same successful reply shape. ```json { "method": "Debugger.scriptParsed", "params": { "scriptId": "1", "url": "node:fs", "executionContextId": 1, "hash": "h", "length": 3, "isModule": false } } ``` 3. Thirty milliseconds after sending the second enable reply, send `{ "bogus": true }`, followed by another well-formed `Debugger.scriptParsed` event with `scriptId: "2"`, `url: "node:path"`, `executionContextId: 1`, `hash: "later"`, `length: 4` and `isModule: false`. 4. Call `new V8InspectorProvider().observe({ inspector_endpoint: "http://127.0.0.1:9230", target_id: "target", observation_ms: 250 })` in a focused integration test. Compare with a control that sends the identical sequence except for the malformed message. ## Expected behavior A fatal protocol parsing error inside the active observation window returns `protocol_error`, with the previously collected script and context metadata retained as a partial observation. An otherwise identical session containing only valid frames finishes successfully and retains both script events. ## Actual behavior The malformed-message run returned `ok: true`, one script, two observed events, zero dropped events and `truncated: false`. The later valid script event was absent. The control returned success with both scripts and three events. Each fixture was run once; the assertion requiring an error for the malformed-message fixture failed. ## Evidence - Expected source: `src/browser/CdpConnection.ts:106` defines fatal parsing failure notification even without pending commands, and `src/browser/execution/CdpExecutionCollection.ts:46` propagates that failure during browser capture. `AGENTS.md` requires preserving partial facts and meaningful failure reasons; `src/inspector/V8InspectorProvider.ts:199` already preserves partial observations for typed capture failures. - Failure source: `src/inspector/V8InspectorProvider.ts:512` waits for the duration or disconnect only. `src/browser/CdpConnection.ts:227` treats the supplied message as a fatal invalid envelope, suppresses subsequent events and leaves the socket open. The focused loopback fixture returned the successful result recorded above. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete ## Restoration check Run the delayed malformed-message fixture after both enable replies and receive `protocol_error` with the first script and execution context preserved as a partial observation. Run the all-valid control and retain both scripts in a successful observation. Keep the malformed frame out of the command-reply interval so a pending command rejection cannot mask the idle-window failure. ## Runtime or environment Source baseline 8b181716aca2cb467be499cba226abfb5ae19141. Node v26.10.0, npm 11.19.1 and lockfile-installed dependencies. The focused test used a local HTTP/WebSocket fixture; no live runtime target was observed. ## Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A bounded protocol failure makes an interrupted observation appear successful and suppresses later script metadata. The fixture directly demonstrated the loss; real-endpoint frequency is unknown. - Workaround status: none - Workaround basis: The result contains no protocol error or truncation signal, so a caller cannot reliably identify this interruption from the returned observation or select a request option that detects it.
bsakaguchi 2026-10-15 18:29:01 +00:00
Author
Owner

@morluto commented on GitHub (Oct 14, 2026):

Addressed on main in 55778f20bacffe428e2cddcff81ffe01c0d477ae.

Fatal Inspector protocol failures are observed during the capture wait and retain available partial observations.

Validation: Affected suites passed in the merged 65-file run (1169 passed, 2 explicit skips), with full static/architecture checks and documentation checks passing. Final installed-package verification is recorded separately in the audit.

Verification scope: Controlled source and production-boundary verification on macOS with pinned Node 24.18.0; real external engines and Windows hosts were not independently rerun. Closure covers the described source defect, not broader provider conformance or performance.

<!-- gh-comment-id:6159221162 --> @morluto commented on GitHub (Oct 14, 2026): Addressed on main in [55778f20bacffe428e2cddcff81ffe01c0d477ae](https://github.com/morluto/rea/commit/55778f20bacffe428e2cddcff81ffe01c0d477ae). Fatal Inspector protocol failures are observed during the capture wait and retain available partial observations. Validation: Affected suites passed in the merged 65-file run (1169 passed, 2 explicit skips), with full static/architecture checks and documentation checks passing. Final installed-package verification is recorded separately in the audit. Verification scope: Controlled source and production-boundary verification on macOS with pinned Node 24.18.0; real external engines and Windows hosts were not independently rerun. Closure covers the described source defect, not broader provider conformance or performance.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#854
No description provided.