affaan-m/ECC · error · Error
end requires a file path
Error message
end requires a file path
What it means
Thrown by cmdEnd when the `end` subcommand is called without a positional file path. The end command POSTs to `/api/end` with `path.resolve(file)`, so a file is mandatory to identify which review session to terminate. It is the agent-side way to close a session after delivering final updates.
Source
Thrown at scripts/plan-canvas.js:329
// Report feedback the human sent that no agent has picked up yet. Reads state
// directly so it answers even when the server has idled out.
function cmdPending({ stateDir }) {
const store = createSessionStore({ stateDir });
const waiting = store
.list()
.filter(session => session.status !== 'ended' && session.pending > 0)
.map(session => ({ file: session.file, pending: session.pending, updatedAt: session.updatedAt }));
return {
status: waiting.length ? 'pending' : 'clear',
sessions: waiting,
next_step: waiting.length
? 'Run `ecc-plan-canvas await <file>` for each file above to receive the messages.'
: 'No canvas feedback is waiting.'
};
}
async function cmdEnd(file, { port }) {
if (!file) throw new Error('end requires a file path');
if (!(await healthCheck(port))) return { status: 'no-server' };
const res = await request(port, 'POST', '/api/end', { file: path.resolve(file) });
return res.body;
}
async function cmdStop({ stateDir, port }) {
if (!(await healthCheck(port))) return { status: 'not running' };
await request(port, 'POST', '/shutdown').catch(() => {});
fs.rmSync(serverInfoPath(stateDir), { force: true });
return { status: 'stopping' };
}
async function cmdServer(args, { stateDir, port }) {
const portArg = valueAfter(args, '--port');
const hostArg = valueAfter(args, '--host');
const listenPort = portArg !== null ? Number.parseInt(portArg, 10) : port;
const store = createSessionStore({ stateDir });
let shuttingDown = false;View on GitHub (pinned to 01e15490f0)
Solutions
- Pass the file: `node scripts/plan-canvas.js end .claude/plans/feature.plan.md`.
- If you need to stop the whole server regardless of session, use `node scripts/plan-canvas.js stop` instead.
- Track open files in your orchestrator so the end call always has a concrete path.
Example fix
// before node scripts/plan-canvas.js end // after node scripts/plan-canvas.js end .claude/plans/feature.plan.md
Defensive patterns
Strategy: validation
Validate before calling
function validateEndFile(file) {
if (typeof file !== 'string' || file.trim() === '') {
throw new Error('cmdEnd: file argument is required');
}
return file;
} Type guard
function isEndFile(arg) {
return typeof arg === 'string' && arg.length > 0 && !arg.startsWith('--');
} Try / catch
try {
await cmdEnd(file, ctx);
} catch (err) {
if (err.message === 'end requires a file path') {
console.error('Usage: node scripts/plan-canvas.js end <file>');
process.exit(2);
}
throw err;
} Prevention
- Use `stop` (no file) to shut the whole server; use `end <file>` for one session.
- Track open files in the orchestrator so end always has a concrete path.
- Make end idempotent-safe by tolerating 'session not found' from the server.
When it happens
Trigger: Running `node scripts/plan-canvas.js end` with no file; passing a flag in the file slot; a cleanup hook that calls end generically without knowing which plan was open.
Common situations: Agent shutdown routine calls `end` for all sessions but one file variable was empty; user misreads usage and thinks `end` with no arg ends all; orphaned session from a crashed `open` that the caller tries to end by name that no longer exists.
Related errors
- open requires a file path
- await requires a file path
- typing requires a file path
- Unknown argument: ${arg}
- Unknown argument: ${arg}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/338010ee18720f92.
Report an issue: GitHub.