{"record":{"id":"f8db3b4d020c5041","repo":"stablyai/orca","slug":"could-not-read-physical-footprint-for-pids-pids","errorCode":null,"errorMessage":"Could not read physical footprint for PIDs ${pids.join(', ')}","messagePattern":"Could not read physical footprint for PIDs (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"config/scripts/hang-watchdog-process-metrics.mjs","lineNumber":53,"sourceCode":"export function parsePhysicalFootprintBytes(output, processCount) {\n  const match =\n    processCount > 1\n      ? output.match(/^Summary Footprint:\\s+(\\d+) B$/m)\n      : output.match(/^[^\\s].*\\sFootprint:\\s+(\\d+) B/m)\n  const bytes = Number(match?.[1])\n  return Number.isFinite(bytes) && bytes > 0 ? bytes : null\n}\n\nexport function physicalFootprintBytes(pids) {\n  const pidArgs = pids.flatMap((pid) => ['--pid', String(pid)])\n  const output = execFileSync(\n    '/usr/bin/footprint',\n    [...pidArgs, '--format', 'bytes', '--noCategories'],\n    { encoding: 'utf8' }\n  )\n  const bytes = parsePhysicalFootprintBytes(output, pids.length)\n  if (bytes === null) {\n    throw new Error(`Could not read physical footprint for PIDs ${pids.join(', ')}`)\n  }\n  return bytes\n}\n\nexport function parseProcessCpuTimeMs(raw) {\n  if (!raw.trim()) {\n    return null\n  }\n  const parts = raw.split(':').map(Number)\n  if (!parts.length || parts.some((part) => !Number.isFinite(part))) {\n    return null\n  }\n  const seconds = parts.reduce((total, part) => total * 60 + part, 0)\n  const milliseconds = seconds * 1_000\n  return milliseconds >= 0 ? milliseconds : null\n}\n\nfunction processCpuTimeMs(pid) {","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/config/scripts/hang-watchdog-process-metrics.mjs#L35-L71","documentation":"Thrown by physicalFootprintBytes() when `/usr/bin/footprint` runs successfully but its output does not match the expected regex, so no byte count could be parsed. For a single PID it matches `<line> Footprint: <n> B`; for multiple PIDs it matches `Summary Footprint: <n> B`. A null parse result triggers the throw.","triggerScenarios":"One or more PIDs exited before footprint ran, the macOS footprint tool changed its output format across OS versions, or footprint emitted a category/summary layout the regex does not cover.","commonSituations":"Child process exiting mid-measurement, running on a newer/older macOS where footprint output differs, or passing already-dead PIDs.","solutions":["Confirm all PIDs are alive before calling physicalFootprintBytes.","Run `/usr/bin/footprint --pid <pid> --format bytes --noCategories` manually to inspect the actual output format.","If the macOS footprint format changed, update parsePhysicalFootprintBytes regex to match.","Gate the benchmark on a tested macOS version range."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Confirm all PIDs are alive and footprint exists before reading\nimport { existsSync } from 'node:fs'\nif (!existsSync('/usr/bin/footprint')) throw new Error('/usr/bin/footprint not found (macOS only)')\nfor (const pid of pids) { try { process.kill(pid, 0) } catch { throw new Error(`pid ${pid} not alive for footprint`) } }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep all sampled PIDs alive throughout the footprint invocation.","When macOS footprint output format changes, update parsePhysicalFootprintBytes regex and add a regression test."],"tags":["metrics","memory","macos","footprint","process"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}