affaan-m/ECC · error · Error

request failed

Error message

request failed

What it means

Thrown by postWorkItem as a last-resort message when the control-pane POST responded with HTTP 200 and a JSON body whose result.ok is falsy, but result.error is empty/undefined. It means the server signaled failure (ok:false) without giving a reason, so the client cannot surface anything more specific than 'request failed'.

Source

Thrown at scripts/lib/control-pane/ui.js:664

    }

    $('#query-form').addEventListener('submit', event => {
      event.preventDefault();
      state.query = $('#query').value.trim();
      load().catch(error => showError('#app', error));
    });
    $('#refresh').addEventListener('click', () => {
      load().catch(error => showError('#app', error));
    });

    async function postWorkItem(pathSuffix, payload) {
      const response = await fetch('/api/work-items/' + pathSuffix, {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(payload || {})
      });
      const result = await readJsonResponse(response);
      if (!result.ok) throw new Error(result.error || 'request failed');
      await load();
    }

    window.eccClaimItem = function (id) {
      if (!state.allowActions) return;
      const owner = window.prompt('Claim "' + id + '" as (owner name):');
      if (!owner) return;
      const as = (window.prompt("Owner kind: 'agent' or 'human'", 'human') || '').trim().toLowerCase();
      postWorkItem(encodeURIComponent(id) + '/claim', { owner: owner.trim(), as: as === 'agent' ? 'agent' : 'human' })
        .catch(error => showError('#app', error));
    };
    window.eccMoveItem = function (id, lane) {
      if (!state.allowActions) return;
      postWorkItem(encodeURIComponent(id) + '/move', { lane })
        .catch(error => showError('#app', error));
    };

    // Live board: refresh on a gentle interval; pause while a prompt/tab is hidden.

View on GitHub (pinned to 01e15490f0)

Solutions

  1. On the server, always populate result.error (and result.reason) whenever ok is false so the client has something actionable.
  2. On the client, surface result.reason || result.error before falling back, and log the full result object for diagnosis.
  3. Reproduce with curl -X POST /api/work-items/<id>/<action> -H 'content-type: application/json' -d '{}' and inspect the JSON response.
  4. Check whether allowActions gating or another precondition returned ok:false intentionally.

Example fix

// before
if (!result.ok) throw new Error(result.error || 'request failed');

// after — surface any reason the server gave
if (!result.ok) {
  const detail = result.error || result.reason || `request failed (${JSON.stringify(result)})`;
  throw new Error(detail);
}
Defensive patterns

Strategy: validation

Validate before calling

function assertOk(result) {
  if (!result || result.ok === false) {
    const detail = (result && (result.error || result.reason)) || 'request failed (no reason supplied)';
    throw new Error(detail);
  }
}

Type guard

function isOkResult(result) {
  return result && result.ok === true;
}

Try / catch

try {
  await postWorkItem(path, payload);
} catch (e) {
  if (e.message === 'request failed') {
    // server returned ok:false with no error; inspect network/response in devtools
  }
  throw e;
}

Prevention

When it happens

Trigger: A work-item mutation route (claim, move, etc.) returns { ok:false } with no error field; readJsonResponse passed because the body was valid JSON and response.ok was true, but the application-level success flag was false and the reason field was omitted.

Common situations: Server-side handler short-circuited (e.g. state.allowActions was false) and returned { ok:false } without populating error; a refactor changed the response shape from { error } to { reason } so the client's fallback kicks in; the route returns ok:false on a no-op but forgets to attach a message.

Related errors


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