affaan-m/ECC · warning · Error

typing requires a file path

Error message

typing requires a file path

What it means

Thrown by cmdTyping when the `typing` subcommand is called without a positional file path. The typing command POSTs an activity/presence indicator to a per-file review session (`/api/session/<key>/typing`), so the session key is derived from the file and cannot be omitted. It is a fire-and-forget presence signal meant to cheaply show the agent is working.

Source

Thrown at scripts/plan-canvas.js:302

  process.stderr.write('[plan-canvas] waiting for human feedback... leave this running (re-run if interrupted; queued feedback is never lost)\n');
  const result = await awaitRequest(port, sessionKeyFor(canonicalizeArtifactPath(file)), timeoutMs);
  if (result.status === 'feedback') {
    result.next_step = result.sessionEnded
      ? 'The user sent this feedback and ended the session. Address it and report in chat; do not reopen the canvas uninvited.'
      : 'Address the feedback, then run `ecc-plan-canvas await <file> --reply "<what you changed>"` to answer in the canvas and keep listening.';
  } else if (result.status === 'ended') {
    result.next_step =
      result.endedBy === 'user'
        ? 'The user ended this review. Stop polling and deliver any remaining updates in chat; do not reopen uninvited.'
        : 'Session ended. Stop polling.';
  }
  return result;
}

// Show the human an activity indicator in the canvas chat. Cheap and
// fire-and-forget: a failed signal must never derail the actual work.
async function cmdTyping(file, args, { port }) {
  if (!file) throw new Error('typing requires a file path');
  const state = valueAfter(args, '--state') || 'typing';
  if (!(await healthCheck(port))) return { status: 'no-server' };
  const key = sessionKeyFor(canonicalizeArtifactPath(file));
  const res = await request(port, 'POST', `/api/session/${key}/typing`, { state });
  if (res.statusCode !== 200) throw new Error(res.body.error || `typing failed (HTTP ${res.statusCode})`);
  return { status: 'ok', state, presence: res.body.presence };
}

// 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',

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Provide the file whose session you want to signal: `node scripts/plan-canvas.js typing .claude/plans/feature.plan.md`.
  2. Ensure `open <file>` ran first so a session exists for that key.
  3. Treat typing failures as non-fatal in the caller — the source comment says a failed signal must never derail the work, so wrap the call and ignore errors when the file is unknown.

Example fix

// before
node scripts/plan-canvas.js typing --state thinking
// after
node scripts/plan-canvas.js typing .claude/plans/feature.plan.md --state thinking
Defensive patterns

Strategy: validation

Validate before calling

function validateTypingFile(file) {
  if (typeof file !== 'string' || file.trim() === '') {
    throw new Error('cmdTyping: file argument is required');
  }
  return file;
}

Type guard

function isTypingFile(arg) {
  return typeof arg === 'string' && arg.length > 0 && !arg.startsWith('--');
}

Try / catch

// Presence signals must never break the parent workflow
try {
  await cmdTyping(file, args, ctx);
} catch (err) {
  console.error(`[plan-canvas] typing signal skipped: ${err.message}`);
  // continue regardless
}

Prevention

When it happens

Trigger: Calling `node scripts/plan-canvas.js typing` with only `--state` and no file; an agent loop that sends typing pings but lost the file reference; typo'ing the subcommand order so a flag lands where the file belongs.

Common situations: Agent orchestrator passes an optional file that was undefined for this turn; user copies the typing example but drops the path; session was never `open`ed so the caller assumes no file needed.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/9912c83e6ca0736f. Report an issue: GitHub.