affaan-m/ECC · error · Error

Expected JSON response from control pane

Error message

Expected JSON response from control pane: ${error.message}

What it means

readJsonResponse parses the fetch response body as JSON. When response.json() rejects (empty body, HTML error page, truncated stream), it rethrows as 'Expected JSON response from control pane: <reason>'. This distinguishes parse failures from HTTP status errors, which are handled separately below.

Solutions

  1. Inspect error.message suffix for the underlying parse failure (e.g. 'Unexpected end of JSON input' means empty/truncated body).
  2. Check the server logs for the /api/work-items request — a 5xx with HTML body is the usual culprit.
  3. Confirm the endpoint route exists and always returns NextResponse.json(...), never res.end() or a redirect.
  4. Retry the action once the server is healthy; this is typically transient infrastructure, not client code.

Example fix

// before
payload = await response.json();
// after
const text = await response.text();
try { payload = text ? JSON.parse(text) : null; }
catch (error) { throw new Error('Expected JSON response from control pane: ' + error.message); }
Defensive patterns

Strategy: try-catch

Validate before calling

const ct = response.headers.get('content-type') || '';
if (!ct.includes('application/json')) throw new Error('Non-JSON response: ' + ct);

Type guard

function isJsonBody(res) { return (res.headers.get('content-type') || '').includes('application/json'); }

Try / catch

try { const result = await readJsonResponse(response); } catch (e) {
  if (String(e.message).startsWith('Expected JSON response')) {
    console.error('Control pane returned non-JSON body; check server/proxy logs', e.message);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling any control-pane action (e.g. window.eccClaimItem posting to /api/work-items/...) where the server returns a non-JSON body: empty response, HTML 502 page from a proxy, or an aborted/stream error mid-read.

Common situations: Dev server restarting mid-request, a reverse proxy (nginx/cloudflare) returning an HTML error page, server route crashing before writing a body, or network interruption during response streaming.

Understand the failure class

Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

      const target = $(targetSelector);
      if (!target) return;
      target.hidden = false;
      target.textContent = formatError(error);
    }

    function clearError(targetSelector) {
      const target = $(targetSelector);
      if (!target) return;
      target.hidden = true;
      target.textContent = '';
    }

    async function readJsonResponse(response) {
      let payload;
      try {
        payload = await response.json();
      } catch (error) {
        throw new Error('Expected JSON response from control pane: ' + error.message);
      }

      if (!response.ok) {
        const detail = payload && payload.error ? payload.error : response.status + ' ' + response.statusText;
        throw new Error(detail);
      }

      return payload;
    }

    function statePill(stateName) {
      const state = String(stateName || 'unknown');
      const klass = ['running', 'done'].includes(state)
        ? 'good'
        : ['failed', 'blocked'].includes(state)
          ? 'bad'
          : ['pending', 'ready'].includes(state)
            ? 'warn'

View on GitHub (pinned to 8321021c54)