{"record":{"id":"927895ce4495ff8f","repo":"affaan-m/ECC","slug":"open-requires-a-file-path","errorCode":null,"errorMessage":"open requires a file path","messagePattern":"open requires a file path","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/plan-canvas.js","lineNumber":225,"sourceCode":"    return false;\n  }\n}\n\nfunction output(payload) {\n  process.stdout.write(`${JSON.stringify(payload, null, 2)}\\n`);\n}\n\nasync function cmdStatus({ stateDir, port }) {\n  const health = await healthCheck(port);\n  if (!health) {\n    return { server: 'not running', hint: 'open an artifact to start one', stateDir };\n  }\n  const sessions = await request(port, 'GET', '/api/sessions');\n  return { server: `http://${DEFAULT_HOST}:${port}`, version: health.version, sessions: sessions.body.sessions };\n}\n\nasync function cmdOpen(file, args, { stateDir, port }) {\n  if (!file) throw new Error('open requires a file path');\n  if (!fs.existsSync(path.resolve(file))) throw new Error(`artifact not found: ${file}`);\n  await ensureServer({ stateDir, port });\n  const res = await request(port, 'POST', '/api/sessions', {\n    file: path.resolve(file),\n    reopen: args.includes('--reopen')\n  });\n  if (res.statusCode === 409) return res.body;\n  if (res.statusCode !== 200) throw new Error(res.body.error || `open failed (HTTP ${res.statusCode})`);\n  const url = `http://${DEFAULT_HOST}:${port}${res.body.url}`;\n  const launched = args.includes('--no-open') ? false : openBrowser(url);\n  return {\n    status: 'open',\n    url,\n    browser: launched ? 'opened' : 'not opened',\n    next_step:\n      'Run `ecc-plan-canvas await <file>` and leave it running; it returns when the human sends feedback, a verdict, or ends the session.'\n  };\n}","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/plan-canvas.js#L207-L243","documentation":"Thrown by cmdOpen in scripts/plan-canvas.js when the `open` subcommand is invoked with no file path argument. The first positional arg is the artifact file to open in the review canvas; omitting it is rejected before any server interaction. (A non-existent but supplied path hits a separate 'artifact not found' error.)","triggerScenarios":"Running `node scripts/plan-canvas.js open` with no trailing file, or with only flags (`open --no-open`). The file is read from args[0] after the command is shifted off; if it is undefined, this throws.","commonSituations":"A wrapper script that conditionally includes the file path; a shell variable for the path that expanded to empty; copy-pasting the usage line and forgetting to substitute a real path.","solutions":["Pass a file path: `node scripts/plan-canvas.js open .claude/plans/feature.plan.md`.","Quote shell variables so an empty path is caught at the call site (`[ -n \"$FILE\" ] || exit 1`).","Use an absolute or repo-relative path; the command resolves it with path.resolve."],"exampleFix":"// before\nnode scripts/plan-canvas.js open --no-open\n// after\nnode scripts/plan-canvas.js open .claude/plans/feature.plan.md --no-open","handlingStrategy":"validation","validationCode":"function assertFileArg(file) {\n  if (typeof file !== 'string' || file.length === 0) {\n    throw new Error('open requires a non-empty file path');\n  }\n  return file;\n}","typeGuard":"function isNonEmptyString(value) {\n  return typeof value === 'string' && value.length > 0;\n}","tryCatchPattern":null,"preventionTips":["Quote shell variables holding the path so empty expansions are caught early.","In wrappers, assert the file exists before invoking `open` to get a clearer error.","Treat a missing path as a configuration failure, not a runtime retry."],"tags":["cli","plan-canvas","argument-validation"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}