affaan-m/ECC · error · Error
Control-plane request failed
Error message
Control-plane request failed
What it means
The control-plane view polls /api/control-plane and throws 'Control-plane request failed' whenever the fetch resolves but the HTTP response is not ok (non-2xx). The poll's catch handler then sets the status display to 'offline', so users see the dashboard go offline while the server is erroring.
Solutions
- Check the control-plane server logs for the error behind the non-2xx response
- Verify the page is served from the same server that exposes /api/control-plane (correct --host/--port)
- Curl /api/control-plane directly and inspect the status code and body
- Restart the control-plane server or fix the failing snapshot endpoint
Example fix
// before
fetch('/api/control-plane').then(r => { if (!r.ok) throw new Error('Control-plane request failed'); ... });
// after
fetch('/api/control-plane').then(r => {
if (!r.ok) throw new Error(`Control-plane request failed: HTTP ${r.status}`);
return r.json();
}).then(apply).catch(err => { setStatus('offline'); console.warn(err.message); }); Defensive patterns
Strategy: try-catch
Validate before calling
const res = await fetch('/api/control-plane');
if (!res.ok) console.warn('control-plane HTTP', res.status); // decide before calling apply Type guard
const isHealthy = (r) => r.ok;
Try / catch
fetch('/api/control-plane')
.then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.json(); })
.then(apply)
.catch(err => { setStatus('offline'); console.warn('control-plane unreachable:', err.message); }); Prevention
- Monitor the control-plane server process health
- Serve the UI and API from the same host/port
- Check proxy (nginx/traefik) upstream configs
- Add alerting on repeated non-2xx /api/control-plane responses
When it happens
Trigger: fetch('/api/control-plane') returns r.ok === false — e.g. 500 from a server-side snapshot failure, 404 after the route was moved, or 502/503 from a proxy while the control-plane server restarts.
Common situations: Control-plane server crashed or is restarting; wrong port/host so requests hit another service; API route renamed in an upgrade; proxy (nginx/traefik) returning 502 when the upstream is down.
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
- download declares an invalid or excessive size
- download exceeds maximum allowed size
- download length does not match declared size
- download length does not match declared size
- Missing HTTP method
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/062f6f826c4c8189.
Report an issue: GitHub.
Appendix: source
Thrown at scripts/lib/control-pane/control-plane-view-ui.js:227
function apply(data) {
if (!data || data.schemaVersion !== 'ecc.control-plane.view.v1' ||
!['tasks', 'lanes', 'pairs', 'events'].every(function (key) { return Array.isArray(data[key]); }) ||
!data.projection || !Array.isArray(data.projection.agents) || !data.thresholds ||
!Number.isFinite(data.thresholds.ta) || !Number.isFinite(data.thresholds.ra)) {
throw new Error('Invalid control-plane view');
}
view = Object.assign({}, data);
renderEvents(); renderLanes(); draw();
var c = view.counts || {};
document.getElementById('status').textContent =
(c.tasks || 0) + ' tasks in ' + (c.lanes || 0) + ' lanes | ' + (c.agents || 0) + ' with edits | ' +
(c.advisories || 0) + ' advisories (' + (c.resolutions || 0) + ' steering)' +
(view.inventory && view.inventory.status !== 'ok' ? ' | inventory ' + view.inventory.status : '');
}
function poll() {
fetch('/api/control-plane').then(function (r) {
if (!r.ok) throw new Error('Control-plane request failed');
return r.json();
}).then(apply).catch(function () {
document.getElementById('status').textContent = 'offline';
});
}
resize();
poll();
setInterval(poll, 5000);
})();
</script>
</body>
</html>`;
}
module.exports = { renderControlPlaneViewHtml };
View on GitHub (pinned to 8321021c54)