{"record":{"id":"75a791f92356b372","repo":"Hmbown/CodeWhale","slug":"output-path-must-be-an-absolute-filename","errorCode":null,"errorMessage":"output path must be an absolute filename","messagePattern":"output path must be an absolute filename","errorType":"validation","errorClass":"ExecError","httpStatus":null,"severity":"error","filePath":"crates/tui/plugins/computer-use/src/backends/linux.mjs","lineNumber":55,"sourceCode":"\nfunction appName(ref) {\n  if (ref === undefined) return \"\";\n  if (!ref || typeof ref !== \"object\" || Array.isArray(ref) || Object.keys(ref).length !== 1 || typeof ref.name !== \"string\" || !ref.name.trim()) {\n    throw Object.assign(new ExecError(\"Linux accessibility targeting supports only a nonblank app_ref.name; PID and bundle selectors are unavailable\"), { code: \"unsupported_selector\" });\n  }\n  return ref.name;\n}\n\nfunction rejectWindowSelectors(args) {\n  if (Object.hasOwn(args, \"app_ref\") || Object.hasOwn(args, \"window_id\")) throw Object.assign(new ExecError(\"Linux window listing and screenshots do not support app_ref or window_id selectors\"), { code: \"unsupported_selector\" });\n}\n\nfunction assertAppRootWindow(index, windowId) {\n  if (windowId !== undefined || (index !== undefined && index !== 0)) throw Object.assign(new ExecError(\"Linux accessibility paths start at the app root; window selectors are unavailable\"), { code: \"unsupported_selector\" });\n}\n\nfunction outputPath(file) {\n  if (typeof file !== \"string\" || !path.isAbsolute(file) || file.includes(\"\\0\")) throw new ExecError(\"output path must be an absolute filename\");\n  return file;\n}\n\nexport function create({ exec } = {}) {\n  const run = exec?.run ?? nativeRun;\n  const have = exec?.have ?? nativeHave;\n  const browser = createBrowser({ platform: \"linux\" });\n  function requireInputOwner() {\n    if (exec?.persistentInputOwner !== true) throw Object.assign(new ExecError(\n      \"This held-input gesture requires a connected Codewhale Computer Use desktop helper so a disconnected client cannot leave keys or buttons pressed. Start the helper and reconnect before retrying.\"\n    ), { code: \"input_owner_required\" });\n  }\n\n  const tools = {};\n  let session = null; // \"x11\" | \"wayland\"\n  let probed = false;\n  let lastRaster = null;\n  let mouseHeld = false;","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/plugins/computer-use/src/backends/linux.mjs#L37-L73","documentation":"`outputPath` validates that every file the Linux backend writes (screenshots, recordings) is an absolute path string containing no NUL byte. Relative paths and non-string inputs are rejected so files land in a deterministic location regardless of the backend process's working directory.","triggerScenarios":"Calling a capture/recording API (e.g. `takeShot`/screenshot with `file`) with a relative path like \"shot.png\", an empty string, a non-string value, or a path containing \"\\0\" (backends/linux.mjs:55).","commonSituations":"Passing a filename from CLI args without resolving it; assuming the process cwd applies; concatenating user input into a path.","solutions":["Resolve the path to absolute before calling: `path.resolve(\"shot.png\")`.","Use path.join(os.homedir(), ...) or another absolute base directory.","Validate the input is a non-empty string before passing it."],"exampleFix":"// before\nawait backend.screenshot({ file: \"shot.png\" }); // throws\n// after\nimport path from \"node:path\";\nawait backend.screenshot({ file: path.resolve(\"shot.png\") });","handlingStrategy":"validation","validationCode":"function assertAbsoluteOut(p) {\n  if (typeof p !== \"string\" || !path.isAbsolute(p) || p.includes(\"\\0\"))\n    throw new TypeError(\"output path must be an absolute filename\");\n}","typeGuard":"const isSafeAbsPath = (p) => typeof p === \"string\" && path.isAbsolute(p) && !p.includes(\"\\0\");","tryCatchPattern":"try { await backend.screenshot({ file }); }\ncatch (e) {\n  if (String(e.message).includes(\"absolute filename\")) file = path.resolve(file);\n  else throw e;\n}","preventionTips":["Always path.resolve() user-supplied output filenames","Use a fixed absolute output directory","Reject relative paths at your app's config boundary"],"tags":["path-validation","absolute-path","argument"],"backgroundTag":"invalid-argument-value","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"}