affaan-m/ECC · error · Error
request failed
Error message
request failed
What it means
Work-item action posts return { ok: boolean, error?: string }. When the handler completes successfully at HTTP level but reports ok:false, the client throws result.error or the generic 'request failed' fallback. This is a business-logic failure, not an HTTP failure.
Solutions
- Look at the server handler for the endpoint and find which path returns ok:false; the generic message means the error field was missing.
- Ensure handlers always include an error string when ok is false: { ok: false, error: reason }.
- Re-check the work item state — the mutation may have been rejected because the item is done, claimed, or missing.
- Retry the action after refreshing the control pane state.
Example fix
// before (server handler)
return res.json({ ok: false });
// after
return res.json({ ok: false, error: 'no-unassigned-open-items' }); Defensive patterns
Strategy: type-guard
Validate before calling
const result = await readJsonResponse(response);
if (typeof result.ok !== 'boolean') throw new Error('Malformed API result');
if (!result.ok && !result.error) throw new Error('API failed without error detail'); Type guard
function isActionOk(r) { return !!r && r.ok === true; } Try / catch
try { await action(); } catch (e) {
if (e.message === 'request failed') console.error('Handler returned ok:false without an error message — inspect the server handler.');
else throw e;
} Prevention
- Server handlers must always set an error string when ok is false.
- Add an integration test asserting error payloads include an error field.
- Refresh state before retrying mutations.
- Treat 'request failed' as a handler bug to fix, not a client-side retryable condition.
When it happens
Trigger: POST /api/work-items/<action> whose handler returns { ok: false } without an error message — e.g. mutation helper returned { claimed:false } path collapsed into a falsey ok, or handler omitted the error field.
Common situations: Claiming/moving a work item when the store operation partially fails, or a handler that sets ok:false but forgets to set error, so the UI shows only 'request failed'.
Related errors
- distill failed
- INTERNAL_ERROR
- (payload.error || status + ' ' + statusText)
- ${result.error || 'request failed'}
- Codex review failed ` : ''}
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/bf00c68ee3ed8bc5.
Report an issue: GitHub.
Appendix: 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 8321021c54)