{"record":{"id":"a757e46fc6cd8745","repo":"openclaw/openclaw","slug":"output-path-is-required","errorCode":null,"errorMessage":"output path is required","messagePattern":"output path is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"extensions/browser/src/browser/output-files.ts","lineNumber":19,"sourceCode":"/**\n * Browser output file writer.\n *\n * Validates caller-provided output paths against a root before writing\n * screenshots, PDFs, downloads, or traces to disk.\n */\nimport path from \"node:path\";\nimport { writeExternalFileWithinRoot } from \"../sdk-security-runtime.js\";\nimport { ensureOutputDirectory } from \"./output-directories.js\";\n\n/** Write a browser output file within a caller-selected output root. */\nexport async function writeExternalFileWithinOutputRoot(params: {\n  rootDir?: string;\n  path: string;\n  write: (filePath: string) => Promise<void>;\n}): Promise<string> {\n  const outputPath = params.path.trim();\n  if (!outputPath) {\n    throw new Error(\"output path is required\");\n  }\n\n  const rootDir = params.rootDir\n    ? path.resolve(params.rootDir)\n    : path.dirname(path.resolve(outputPath));\n  await ensureOutputDirectory(rootDir);\n\n  const result = await writeExternalFileWithinRoot({\n    rootDir,\n    path: outputPath,\n    write: params.write,\n  }).catch((err: unknown) => {\n    if (err instanceof Error && (err as NodeJS.ErrnoException).code === \"ENOENT\") {\n      throw new Error(\"output directory changed while writing file\", { cause: err });\n    }\n    throw err;\n  });\n  return result.path;","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/openclaw/openclaw/blob/01804a75319da4b69c9ab98ceaa30477e22b8c0b/extensions/browser/src/browser/output-files.ts#L1-L37","documentation":"Thrown by writeExternalFileWithinOutputRoot when params.path trims to empty. The function writes browser output artifacts (screenshots, PDFs, downloads, traces) to a caller-selected output root and requires a non-empty relative or absolute path. The check runs before rootDir resolution and directory creation.","triggerScenarios":"A browser snapshot, screenshot, PDF, or download action invoked with an empty/whitespace output path; tooling that built the path from an empty variable; a caller that omitted the path field.","commonSituations":"Agents templating the output path from a missing variable; CLI callers that passed --out \"\"; harnesses that drop the output filename; profile configs with a blank default output directory combined with a missing filename.","solutions":["Supply a non-empty output path (filename or absolute path) when invoking the browser output action.","Validate the resolved path in the caller before dispatching the action.","Default to a deterministic filename (e.g. screenshot.png) in the tool layer when the caller omits one."],"exampleFix":"// before\nawait writeExternalFileWithinOutputRoot({ path: '', write: ... });\n// after\nawait writeExternalFileWithinOutputRoot({ path: 'screenshot.png', write: ... });","handlingStrategy":"validation","validationCode":"function requireOutputPath(p: string | undefined): string {\n  const trimmed = (p ?? '').trim();\n  if (!trimmed) throw new Error('output path is required');\n  return trimmed;\n}\n// Pass the validated path to writeExternalFileWithinOutputRoot.","typeGuard":"function isNonEmptyOutputPath(p: unknown): p is string {\n  return typeof p === 'string' && p.trim().length > 0;\n}","tryCatchPattern":"try {\n  await writeExternalFileWithinOutputRoot({ path, write });\n} catch (err) {\n  if (err instanceof Error && err.message === 'output path is required') {\n    path = defaultOutputName(); // e.g. 'screenshot.png'\n    return await writeExternalFileWithinOutputRoot({ path, write });\n  }\n  throw err;\n}","preventionTips":["Default to a deterministic filename in the tool layer when the caller omits one.","Validate the output path at the schema boundary.","Avoid building paths from possibly-empty variables."],"tags":["browser","output","filesystem","validation"],"backgroundTag":null,"analyzedSha":"01804a75319da4b69c9ab98ceaa30477e22b8c0b","analyzedAt":"2026-08-12T04:37:58.197Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}