[GH-ISSUE #3378] [Bug] Malformed worker inventories are reported as empty #1245

Closed
opened 2026-10-16 21:03:15 +00:00 by bsakaguchi · 2 comments
Owner

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

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Process capture or runtime observation

Observed behavior

inspect-web-page returns workers: [] with no worker omission or unavailable marker when Target.getTargets returns a missing inventory or an array containing a malformed entry. The result cannot distinguish failure to enumerate workers from a valid empty worker inventory.

The production CLI reproduction used three simulated producer replies: targetInfos: [], a reply omitting targetInfos, and targetInfos: [null]. Each inspection exited with code 0 and returned workers: []. In every case, unavailable_sections and truncated_sections were empty, and the exclusion array contained only unselected content sections, with no workers entry.

This reproduction establishes production CLI behavior for simulated producer replies. It does not establish that a particular Chrome release naturally returns these malformed inventories.

Reproduction

  1. Start from a clean checkout of the source baseline.
git clone https://github.com/morluto/rea.git
cd rea
git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063
  1. Install the locked dependencies and build the runtime.
npm ci
npm run build:cached

The observed reproduction used dependencies and a compiled runtime that were already present. Dependency installation and build are setup instructions, not additional observed results.

  1. Run the following inline fixture from the checkout root. It starts a loopback HTTP/WebSocket CDP fixture and invokes the compiled CLI three times. The first worker reply contains targetInfos: [], the second omits targetInfos, and the third contains targetInfos: [null]. HTTP discovery still reports one valid selected page in every case. The program isolates REA's home directory and removes its temporary files and server after use. It creates every capture file inline, so no external input files are required.
node --input-type=module <<'JS'
import {createServer} from 'node:http';
import {spawn} from 'node:child_process';
import {createRequire} from 'node:module';
import {mkdtemp, mkdir, writeFile, rm} from 'node:fs/promises';
import {tmpdir} from 'node:os';
import {join, resolve} from 'node:path';
const {WebSocketServer} = createRequire(resolve('package.json'))('ws');
const root=await mkdtemp(join(tmpdir(),'rea-inventory-'));
await mkdir(join(root,'home'));
let endpoint, variant='valid';
const url=()=>`${endpoint}/page`;
const target=()=>({id:'page',type:'page',title:'Fixture',url:url(),attached:false});
const server=createServer((req,res)=>{
 res.setHeader('Content-Type','application/json');
 res.end(JSON.stringify(req.url==='/json/list'?[target()]:{
  Browser:'FixtureChrome/1.0','Protocol-Version':'1.3','User-Agent':'FixtureChrome',
  'V8-Version':'1.0','WebKit-Version':'fixture',
  webSocketDebuggerUrl:endpoint.replace('http:','ws:')+'/devtools/browser/fixture'
 }));
});
const sockets=new WebSocketServer({server});
sockets.on('connection',socket=>socket.on('message',raw=>{
 const c=JSON.parse(raw);let result={};
 switch(c.method){
  case 'Target.attachToTarget':result={sessionId:'session'};break;
  case 'Page.getFrameTree':result={frameTree:{frame:{id:'frame',loaderId:'loader',url:url()}}};break;
  case 'Page.getResourceTree':result={frameTree:{frame:{id:'frame',url:url()},resources:[]}};break;
  case 'DOMSnapshot.captureSnapshot':result={strings:[url(),'#document','HTML'],documents:[{documentURL:0,baseURL:0,nodes:{nodeType:[9,1],nodeName:[1,2],nodeValue:[-1,-1],parentIndex:[-1,0],attributes:[[],[]]}}]};break;
  case 'Accessibility.getFullAXTree':result={nodes:[]};break;
  case 'Target.getTargets':result=variant==='missing'?{}:variant==='malformed'?{targetInfos:[null]}:{targetInfos:[]};break;
  case 'Storage.getUsageAndQuota':result={usage:0,quota:1024,usageBreakdown:[]};break;
 }
 socket.send(JSON.stringify({id:c.id,...(c.sessionId?{sessionId:c.sessionId}:{}),result}));
}));
await new Promise(r=>server.listen(0,'127.0.0.1',r));
endpoint=`http://127.0.0.1:${server.address().port}`;
const cli=args=>new Promise((resolveResult,reject)=>{
 const child=spawn(process.execPath,['scripts/rea.mjs',...args],{env:{...process.env,HOME:join(root,'home')}});
 let output='',errors='';child.stdout.on('data',c=>output+=c);child.stderr.on('data',c=>errors+=c);
 child.on('error',reject);child.on('close',code=>resolveResult({code,output,errors}));
});
try{
 for(const v of ['valid','missing','malformed']){
  variant=v;
  const r=await cli(['inspect-web-page',endpoint,'page','--observation-ms','0','--include-accessibility-text','--json']);
  if(r.code!==0)throw new Error(r.output+r.errors);
  const n=JSON.parse(r.output).normalized_result;
  await writeFile(join(root,`${v}.json`),JSON.stringify({inspection:n}));
  console.log(JSON.stringify({variant:v,exit_code:r.code,accessibility:n.accessibility,workers:n.workers,unavailable:n.completeness.unavailable_sections,truncated:n.completeness.truncated_sections,excluded:n.completeness.excluded}));
 }
}finally{
 for(const socket of sockets.clients)socket.terminate();
 await new Promise(r=>sockets.close(r));await new Promise(r=>server.close(r));
 await rm(root,{recursive:true,force:true});
}
JS
  1. Compare the three printed worker and completeness projections. The valid empty reply, missing inventory, and malformed entry all return an empty worker list without a workers coverage marker.

Expected behavior

An explicit empty target array can establish an empty worker inventory within the selected capture. Missing or malformed target enumeration cannot establish worker absence. REA should reject the malformed producer result or record an unavailable/incomplete workers section while preserving any usable, in-scope workers in a partial result. The pre-attach limitations on network and console sections do not describe worker enumeration failure.

docs/browser-observation.md:267 requires incomplete or truncated values to be reported. docs/browser-observation.md:297 includes workers among the returned capture inventories and requires validation omissions to appear in completeness. docs/tool-design.md:55 says missing coverage is unknown, not absence.

Impact and scope

P2, supported. The capture reports worker absence without the enumeration evidence needed to establish it. The observed failure is bounded to malformed producer inventories and can mislead browser runtime investigations.

Workaround status is unverified. A fresh capture from a well-formed provider may avoid the failure, but the CLI discards the original malformed inventory and offers no caller option to identify or validate this omission. No practical recovery for an already returned capture was demonstrated.

REA version

6.4.0 (main at 8dde6370d0)

Runtime and platform

Node.js v26.10.0, macOS 27.0.1 arm64. Dependencies and the compiled runtime were already present.

Target and artifact context

A simulated loopback HTTP/WebSocket CDP endpoint with one valid selected page in HTTP discovery. Only the Target.getTargets inventory changes between the valid empty, missing, and malformed cases. The inline program writes each normalized inspection to its own JSON capture file, then removes the capture files, isolated home directory, and server after use. No real Chrome instance emitting these malformed inventories was established.

Interface

CLI

Earliest failure stage

Capture or observation

Relevant output or evidence

The observed CLI result is summarized below; this is a compact projection of the recorded behavior, not a complete stdout transcript.

All three inspections: exit code 0
valid targetInfos: []       -> workers: []
missing targetInfos         -> workers: []
malformed targetInfos: [null] -> workers: []
Every case: unavailable_sections: [], truncated_sections: []
Every case: excluded contains only unselected content sections; no workers entry

The failure evidence is observed, local verification reproduced the failure, and reproduction completeness is complete.

Typed outcome or recovery expected

Repeat the three producer replies. A valid empty inventory should remain empty without a malformed-data marker. The missing inventory and malformed entry must produce a typed failure or explicit incomplete workers coverage. Also retain a valid related worker alongside a malformed entry, with the valid worker preserved and the omitted entry still reflected in coverage. The mixed valid-worker case is a restoration check, not a result claimed by this reproduction.

Analysis or suspected cause

Source-derived reasoning: src/browser/CdpPageCaptureWorkers.ts:33 marks workers unavailable only when the optional command is absent. src/browser/CdpPageCaptureWorkers.ts:34 silently turns missing/non-record inventory data into no loop iterations through src/browser/CdpCaptureValues.ts:20. The executed command above returns the same empty worker result and no worker coverage marker for valid, absent, and malformed target lists.

Additional context

  • Related to #883, which requests richer worker source and runtime ownership evidence; this report concerns completeness of the existing worker enumeration.
  • Related to #2660, closed as completed, which concerns malformed cache-name inventories and storage completeness; this report concerns Target.getTargets and workers coverage.
  • Related to #2556, closed as completed, which concerns invalid Electron child-frame IDs being classified as scope exclusions; this report concerns worker target inventories omitted without a coverage marker.
  • Related to #2553, closed as completed, which concerns DOM array filtering shifting facts between nodes; this report concerns missing or non-record worker inventory entries.
  • Related to #3172, which concerns unavailable redirect metadata in passive capture comparison; this report concerns worker enumeration during capture.
  • Related to #2288, which discusses browsers without HTTP discovery; this reproduction has working HTTP discovery and loses worker enumeration afterward.
Originally created by @coygeek on GitHub (Oct 14, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3378 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Process capture or runtime observation ### Observed behavior `inspect-web-page` returns `workers: []` with no worker omission or unavailable marker when `Target.getTargets` returns a missing inventory or an array containing a malformed entry. The result cannot distinguish failure to enumerate workers from a valid empty worker inventory. The production CLI reproduction used three simulated producer replies: `targetInfos: []`, a reply omitting `targetInfos`, and `targetInfos: [null]`. Each inspection exited with code 0 and returned `workers: []`. In every case, `unavailable_sections` and `truncated_sections` were empty, and the exclusion array contained only unselected content sections, with no workers entry. This reproduction establishes production CLI behavior for simulated producer replies. It does not establish that a particular Chrome release naturally returns these malformed inventories. ### Reproduction 1. Start from a clean checkout of the source baseline. ```sh git clone https://github.com/morluto/rea.git cd rea git checkout 8dde6370d0809ad04cda3342d4e6f290f48aa063 ``` 2. Install the locked dependencies and build the runtime. ```sh npm ci npm run build:cached ``` The observed reproduction used dependencies and a compiled runtime that were already present. Dependency installation and build are setup instructions, not additional observed results. 3. Run the following inline fixture from the checkout root. It starts a loopback HTTP/WebSocket CDP fixture and invokes the compiled CLI three times. The first worker reply contains `targetInfos: []`, the second omits `targetInfos`, and the third contains `targetInfos: [null]`. HTTP discovery still reports one valid selected page in every case. The program isolates REA's home directory and removes its temporary files and server after use. It creates every capture file inline, so no external input files are required. ```sh node --input-type=module <<'JS' import {createServer} from 'node:http'; import {spawn} from 'node:child_process'; import {createRequire} from 'node:module'; import {mkdtemp, mkdir, writeFile, rm} from 'node:fs/promises'; import {tmpdir} from 'node:os'; import {join, resolve} from 'node:path'; const {WebSocketServer} = createRequire(resolve('package.json'))('ws'); const root=await mkdtemp(join(tmpdir(),'rea-inventory-')); await mkdir(join(root,'home')); let endpoint, variant='valid'; const url=()=>`${endpoint}/page`; const target=()=>({id:'page',type:'page',title:'Fixture',url:url(),attached:false}); const server=createServer((req,res)=>{ res.setHeader('Content-Type','application/json'); res.end(JSON.stringify(req.url==='/json/list'?[target()]:{ Browser:'FixtureChrome/1.0','Protocol-Version':'1.3','User-Agent':'FixtureChrome', 'V8-Version':'1.0','WebKit-Version':'fixture', webSocketDebuggerUrl:endpoint.replace('http:','ws:')+'/devtools/browser/fixture' })); }); const sockets=new WebSocketServer({server}); sockets.on('connection',socket=>socket.on('message',raw=>{ const c=JSON.parse(raw);let result={}; switch(c.method){ case 'Target.attachToTarget':result={sessionId:'session'};break; case 'Page.getFrameTree':result={frameTree:{frame:{id:'frame',loaderId:'loader',url:url()}}};break; case 'Page.getResourceTree':result={frameTree:{frame:{id:'frame',url:url()},resources:[]}};break; case 'DOMSnapshot.captureSnapshot':result={strings:[url(),'#document','HTML'],documents:[{documentURL:0,baseURL:0,nodes:{nodeType:[9,1],nodeName:[1,2],nodeValue:[-1,-1],parentIndex:[-1,0],attributes:[[],[]]}}]};break; case 'Accessibility.getFullAXTree':result={nodes:[]};break; case 'Target.getTargets':result=variant==='missing'?{}:variant==='malformed'?{targetInfos:[null]}:{targetInfos:[]};break; case 'Storage.getUsageAndQuota':result={usage:0,quota:1024,usageBreakdown:[]};break; } socket.send(JSON.stringify({id:c.id,...(c.sessionId?{sessionId:c.sessionId}:{}),result})); })); await new Promise(r=>server.listen(0,'127.0.0.1',r)); endpoint=`http://127.0.0.1:${server.address().port}`; const cli=args=>new Promise((resolveResult,reject)=>{ const child=spawn(process.execPath,['scripts/rea.mjs',...args],{env:{...process.env,HOME:join(root,'home')}}); let output='',errors='';child.stdout.on('data',c=>output+=c);child.stderr.on('data',c=>errors+=c); child.on('error',reject);child.on('close',code=>resolveResult({code,output,errors})); }); try{ for(const v of ['valid','missing','malformed']){ variant=v; const r=await cli(['inspect-web-page',endpoint,'page','--observation-ms','0','--include-accessibility-text','--json']); if(r.code!==0)throw new Error(r.output+r.errors); const n=JSON.parse(r.output).normalized_result; await writeFile(join(root,`${v}.json`),JSON.stringify({inspection:n})); console.log(JSON.stringify({variant:v,exit_code:r.code,accessibility:n.accessibility,workers:n.workers,unavailable:n.completeness.unavailable_sections,truncated:n.completeness.truncated_sections,excluded:n.completeness.excluded})); } }finally{ for(const socket of sockets.clients)socket.terminate(); await new Promise(r=>sockets.close(r));await new Promise(r=>server.close(r)); await rm(root,{recursive:true,force:true}); } JS ``` 4. Compare the three printed worker and completeness projections. The valid empty reply, missing inventory, and malformed entry all return an empty worker list without a workers coverage marker. ### Expected behavior An explicit empty target array can establish an empty worker inventory within the selected capture. Missing or malformed target enumeration cannot establish worker absence. REA should reject the malformed producer result or record an unavailable/incomplete workers section while preserving any usable, in-scope workers in a partial result. The pre-attach limitations on network and console sections do not describe worker enumeration failure. `docs/browser-observation.md:267` requires incomplete or truncated values to be reported. `docs/browser-observation.md:297` includes workers among the returned capture inventories and requires validation omissions to appear in completeness. `docs/tool-design.md:55` says missing coverage is unknown, not absence. ### Impact and scope P2, supported. The capture reports worker absence without the enumeration evidence needed to establish it. The observed failure is bounded to malformed producer inventories and can mislead browser runtime investigations. Workaround status is unverified. A fresh capture from a well-formed provider may avoid the failure, but the CLI discards the original malformed inventory and offers no caller option to identify or validate this omission. No practical recovery for an already returned capture was demonstrated. ### REA version 6.4.0 (main at 8dde6370d0809ad04cda3342d4e6f290f48aa063) ### Runtime and platform Node.js v26.10.0, macOS 27.0.1 arm64. Dependencies and the compiled runtime were already present. ### Target and artifact context A simulated loopback HTTP/WebSocket CDP endpoint with one valid selected page in HTTP discovery. Only the `Target.getTargets` inventory changes between the valid empty, missing, and malformed cases. The inline program writes each normalized inspection to its own JSON capture file, then removes the capture files, isolated home directory, and server after use. No real Chrome instance emitting these malformed inventories was established. ### Interface CLI ### Earliest failure stage Capture or observation ### Relevant output or evidence The observed CLI result is summarized below; this is a compact projection of the recorded behavior, not a complete stdout transcript. ```text All three inspections: exit code 0 valid targetInfos: [] -> workers: [] missing targetInfos -> workers: [] malformed targetInfos: [null] -> workers: [] Every case: unavailable_sections: [], truncated_sections: [] Every case: excluded contains only unselected content sections; no workers entry ``` The failure evidence is observed, local verification reproduced the failure, and reproduction completeness is complete. ### Typed outcome or recovery expected Repeat the three producer replies. A valid empty inventory should remain empty without a malformed-data marker. The missing inventory and malformed entry must produce a typed failure or explicit incomplete workers coverage. Also retain a valid related worker alongside a malformed entry, with the valid worker preserved and the omitted entry still reflected in coverage. The mixed valid-worker case is a restoration check, not a result claimed by this reproduction. ### Analysis or suspected cause Source-derived reasoning: `src/browser/CdpPageCaptureWorkers.ts:33` marks workers unavailable only when the optional command is absent. `src/browser/CdpPageCaptureWorkers.ts:34` silently turns missing/non-record inventory data into no loop iterations through `src/browser/CdpCaptureValues.ts:20`. The executed command above returns the same empty worker result and no worker coverage marker for valid, absent, and malformed target lists. ### Additional context - Related to [#883](https://github.com/morluto/rea/issues/883), which requests richer worker source and runtime ownership evidence; this report concerns completeness of the existing worker enumeration. - Related to [#2660](https://github.com/morluto/rea/issues/2660), closed as completed, which concerns malformed cache-name inventories and storage completeness; this report concerns `Target.getTargets` and workers coverage. - Related to [#2556](https://github.com/morluto/rea/issues/2556), closed as completed, which concerns invalid Electron child-frame IDs being classified as scope exclusions; this report concerns worker target inventories omitted without a coverage marker. - Related to [#2553](https://github.com/morluto/rea/issues/2553), closed as completed, which concerns DOM array filtering shifting facts between nodes; this report concerns missing or non-record worker inventory entries. - Related to [#3172](https://github.com/morluto/rea/issues/3172), which concerns unavailable redirect metadata in passive capture comparison; this report concerns worker enumeration during capture. - Related to [#2288](https://github.com/morluto/rea/issues/2288), which discusses browsers without HTTP discovery; this reproduction has working HTTP discovery and loses worker enumeration afterward.
Author
Owner

@matbrgz commented on GitHub (Oct 16, 2026):

Cross-referencing with sibling issue #3376 ([Bug] Missing or malformed accessibility inventories are reported as complete empty trees). Both reports identify the same pattern in inspect-web-page, where malformed or missing CDP responses are silently converted into empty trees/arrays instead of emitting explicit omission or failure markers.

Both reports are consolidated under Cluster I (Web Inspector Silent Drop of Malformed CDP Inventories) in tracker #4330.

<!-- gh-comment-id:6206898086 --> @matbrgz commented on GitHub (Oct 16, 2026): Cross-referencing with sibling issue #3376 (`[Bug] Missing or malformed accessibility inventories are reported as complete empty trees`). Both reports identify the same pattern in `inspect-web-page`, where malformed or missing CDP responses are silently converted into empty trees/arrays instead of emitting explicit omission or failure markers. Both reports are consolidated under **Cluster I (Web Inspector Silent Drop of Malformed CDP Inventories)** in tracker #4330.
Author
Owner

@coygeek commented on GitHub (Oct 18, 2026):

Addressed on main by github.com/morluto/rea@4cc044be68. Worker capture now reports invalid_protocol_value coverage for missing/non-array inventories and malformed entries, while retaining valid workers beside them. A valid empty inventory remains a normal empty result. I checked the source and the included regression cases; I have not rerun the public CLI fixture. Closing as completed.

<!-- gh-comment-id:6244132301 --> @coygeek commented on GitHub (Oct 18, 2026): Addressed on main by https://github.com/morluto/rea/commit/4cc044be68f813e96907e6cedcf422d0a3170de3. Worker capture now reports invalid_protocol_value coverage for missing/non-array inventories and malformed entries, while retaining valid workers beside them. A valid empty inventory remains a normal empty result. I checked the source and the included regression cases; I have not rerun the public CLI fixture. Closing as completed.
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#1245
No description provided.