{"record":{"id":"210729a573992e7e","repo":"Hmbown/CodeWhale","slug":"jpeg-carries-no-frame-header-file","errorCode":null,"errorMessage":"JPEG carries no frame header: ${file}","messagePattern":"JPEG carries no frame header: (.+?)","errorType":"exception","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/darwin.mjs","lineNumber":57,"sourceCode":"    if (head[0] === 0x89 && head.toString(\"ascii\", 1, 4) === \"PNG\") {\n      return { w: head.readUInt32BE(16), h: head.readUInt32BE(20) };\n    }\n    if (head[0] !== 0xff || head[1] !== 0xd8) throw new ExecError(`unrecognized raster format: ${file}`);\n    // Walk JPEG segments to the frame header. SOF0/1/2/3/5..7/9..11/13..15\n    // carry the dimensions; DHT/DQT and the rest are skipped by their length.\n    const size = fs.fstatSync(fd).size;\n    const seg = Buffer.alloc(9);\n    for (let at = 2; at + 9 <= size; ) {\n      fs.readSync(fd, seg, 0, 9, at);\n      if (seg[0] !== 0xff) throw new ExecError(`malformed JPEG at byte ${at}: ${file}`);\n      const marker = seg[1];\n      if (marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc) {\n        return { w: seg.readUInt16BE(7), h: seg.readUInt16BE(5) };\n      }\n      if (marker === 0xd8 || (marker >= 0xd0 && marker <= 0xd9)) { at += 2; continue; }\n      at += 2 + seg.readUInt16BE(2);\n    }\n    throw new ExecError(`JPEG carries no frame header: ${file}`);\n  } finally {\n    fs.closeSync(fd);\n  }\n}\n\n/**\n * Shrink a raster until it fits the single-message budget.\n *\n * A 5K display captures to ~22MB of PNG, which is ~29MB of base64 — past every\n * host limit, so the alternative is handing back a receipt with no picture and\n * a screenshot tool that never shows anything. Downscaling here, before the\n * caller reads the PNG header, keeps coordinates exact by construction:\n * `pixels` comes from the header, `points` stays in screen points, and `scale`\n * is derived from the two, so raster-to-point conversion follows automatically.\n *\n * PNG bytes track pixel count, so the long edge shrinks by the square root of\n * the overshoot. The estimate is verified rather than trusted — screen content\n * compresses unevenly — and gives up rather than shrinking past legibility.","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/darwin.mjs#L39-L75","documentation":"After walking all JPEG segments without encountering an SOFn frame header (0xC0–0xCF excluding DHT/C8/CC variants), `imagePixels` gives up with `JPEG carries no frame header: <file>`. A valid baseline or progressive JPEG must contain exactly one such frame header, so its absence means dimensions cannot be determined.","triggerScenarios":"A JPEG missing its SOF marker — heavily truncated files where the data ends before the frame header is reached, or non-image data that happens to begin with 0xFF 0xD8, or a file whose segment lengths are wrong so the walk terminates early.","commonSituations":"Zero-dimension or degenerate capture output, files that pass the two-byte magic sniff but are not real JPEGs, or truncated downloads/recordings used as screenshots.","solutions":["Re-capture the screenshot; this file has no decodable frame header.","Validate with an image tool (`sips -g pixelHeight file`) before using imagePixels.","Fall back to capturing dimensions from the capture command output instead of parsing the file.","Check the writer that produced the file — a short write likely truncated it before the frame header."],"exampleFix":"// before\\nconst { w, h } = imagePixels(path); // throws if SOF missing\\n// after\\ntry { const { w, h } = imagePixels(path); }\\ncatch (e) { const { width, height } = dimsViaSips(path); }","handlingStrategy":"fallback","validationCode":"const out = childProcess.execFileSync(\"sips\", [\"-g\", \"pixelWidth\", \"-g\", \"pixelHeight\", file], {encoding: \"utf8\"});\\nif (!/pixelWidth:\\s*\\d+/.test(out)) throw new Error(\"undecodable image: \" + file);","typeGuard":null,"tryCatchPattern":"try { return imagePixels(file); } catch (e) { if (/no frame header/.test(e.message)) return dimsViaSips(file); throw e; }","preventionTips":["Validate screenshots decode before relying on parsed dimensions.","Prefer PNG captures, which have a simple fixed header layout.","Detect truncation by comparing file size to the encoder's expected output."],"tags":["image","jpeg","corruption","darwin"],"backgroundTag":"unexpected-response-shape","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}