affaan-m/ECC · error

HTTP + res.status

Error message

HTTP + res.status

What it means

This error comes from the Plan Canvas browser client's feedback queue flush: after POSTing queued feedback items to /api/session/<key>/feedback, the client checks res.ok and throws 'HTTP <status>' when the server returned an error status (400/404/500, etc.). The thrown value's message is literally the string 'HTTP ' + status, so the browser console shows e.g. 'Uncaught (in promise) Error: HTTP 500'.

Solutions

  1. Reload the canvas page to get a fresh session key, then re-submit the feedback.
  2. Check the canvas server logs for the corresponding request to see the 4xx/5xx reason.
  3. If the server was restarted, restart or reconnect your agent session to the canvas so keys realign.
  4. Clear the local feedback queue (page reload with a healthy server) if persisted items are stale/corrupt and keep failing.

Example fix

// before (client throws and drops nothing)
if (!res.ok) throw new Error('HTTP ' + res.status);
// after (caller-side handling: catch, keep queue, surface status)
try { await flushFeedback(queue); }
catch (e) { console.warn('Feedback submit failed:', e.message, '- will retry'); }
// plus: reload the page if the error is HTTP 404 (stale session key)
Defensive patterns

Strategy: try-catch

Validate before calling

// before flushing queued feedback
if (!queue.length) return;
if (typeof navigator !== 'undefined' && !navigator.onLine) {
  console.warn('Offline: feedback will stay queued');
  return;
}
await fetch('/api/session/' + key + '/feedback', { method: 'HEAD' }).then(r => {
  if (r.status === 404) console.warn('Stale session key — reload the page before submitting.');
});

Type guard

function isFreshSession(session) {
  return Boolean(session && session.key && Date.now() - session.startedAt < 6 * 60 * 60 * 1000);
}

Try / catch

try {
  await flushFeedback(queue);
} catch (e) {
  if (/^HTTP 404$/.test(e.message)) {
    console.warn('Session expired (canvas server restarted). Reload the page and re-submit.');
  } else if (/^HTTP \d+$/.test(e.message)) {
    console.warn(`Feedback rejected (${e.message}); items kept in queue for retry.`);
  } else throw e;
}

Prevention

When it happens

Trigger: The feedback POST fails server-side: session key no longer exists (canvas restarted/stale session, 404), malformed queue items (400), or a server error while persisting feedback (500). Also occurs offline or when the canvas server was restarted, losing the session.

Common situations: Leaving a canvas tab open overnight; the server idles out or is restarted, invalidating the session key; submitting a batch of feedback items while the network dropped; a bug in queued item shape after a client/server version mismatch (old tab, new server).

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/c5732c89de07e381. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/plan-canvas/ui.js:385

    if (ended || sending) return;
    const items = queue.slice();
    if (extraItems) items.push(...extraItems);
    const text = input.value.trim();
    if (text) items.push({ kind: 'chat', text });
    if (!items.length) {
      statusEl.textContent = 'Nothing to send yet - annotate the plan or type a message.';
      return;
    }
    sending = true;
    sendBtn.disabled = true;
    statusEl.textContent = 'Sending\\u2026';
    try {
      const res = await fetch('/api/session/' + key + '/feedback', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ items })
      });
      if (!res.ok) throw new Error('HTTP ' + res.status);
      const body = await res.json().catch(() => ({}));
      queue = [];
      persistQueue();
      renderQueue();
      input.value = '';
      // Say what actually happened: a parked agent takes the batch on the
      // spot, otherwise it sits in the queue until the agent checks in.
      statusEl.textContent = body.presence === 'thinking' || body.presence === 'typing'
        ? 'Delivered. Your agent has it.'
        : 'Queued. Your agent picks this up the moment it checks in.';
      if (body.presence) applyPresence(body.presence);
    } catch (err) {
      statusEl.textContent = 'Send failed (' + err.message + ') - is the canvas server still running?';
    } finally {
      sending = false;
      sendBtn.disabled = ended;
    }
  }

View on GitHub (pinned to 8321021c54)