{"record":{"id":"06e09e9410082230","repo":"affaan-m/ECC","slug":"payload-error-status-statustext","errorCode":null,"errorMessage":"(payload.error || status + ' ' + statusText)","messagePattern":"\\(payload\\.error \\|\\| status \\+ ' ' \\+ statusText\\)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/control-pane/ui.js","lineNumber":449,"sourceCode":"\n    function clearError(targetSelector) {\n      const target = $(targetSelector);\n      if (!target) return;\n      target.hidden = true;\n      target.textContent = '';\n    }\n\n    async function readJsonResponse(response) {\n      let payload;\n      try {\n        payload = await response.json();\n      } catch (error) {\n        throw new Error('Expected JSON response from control pane: ' + error.message);\n      }\n\n      if (!response.ok) {\n        const detail = payload && payload.error ? payload.error : response.status + ' ' + response.statusText;\n        throw new Error(detail);\n      }\n\n      return payload;\n    }\n\n    function statePill(stateName) {\n      const state = String(stateName || 'unknown');\n      const klass = ['running', 'done'].includes(state)\n        ? 'good'\n        : ['failed', 'blocked'].includes(state)\n          ? 'bad'\n          : ['pending', 'ready'].includes(state)\n            ? 'warn'\n            : 'blue';\n      return '<span class=\"pill ' + klass + '\">' + escapeHtml(state) + '</span>';\n    }\n\n    function renderMetrics(summary) {","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/control-pane/ui.js#L431-L467","documentation":"After parsing, readJsonResponse checks response.ok. For non-2xx responses it throws the server-supplied payload.error, or falls back to '<status> <statusText>'. This surfaces HTTP-level failures from the control-pane API to the UI caller.","triggerScenarios":"Any POST/GET to /api/work-items/* that the server rejects: 400 bad body, 404 unknown route/id, 500 handler exception — thrown with the API's error string or the status code.","commonSituations":"Stale page posting a work item id that no longer exists (404), invalid lane/action payload (400), or server bug producing 500 with an error field.","solutions":["Read the thrown detail string — it is either the API's error message or the HTTP status; match it to the failing endpoint.","Verify the request payload shape matches what the route handler validates.","Check that the work item / route referenced still exists (stale UI state after another agent moved/deleted it).","Add server-side logging in the route to capture why it returned a non-2xx status."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if (!response.ok) {\n  const body = await response.text();\n  console.error('API failed', response.status, body.slice(0, 500));\n}","typeGuard":"function isApiErrorPayload(p) { return !!p && typeof p === 'object' && typeof p.error === 'string'; }","tryCatchPattern":"try { await postWorkItemAction(path, payload); } catch (e) {\n  if (/^\\d{3} /.test(e.message)) console.error('HTTP failure:', e.message);\n  else throw e;\n}","preventionTips":["Always return a JSON error body with an error field from API routes.","Keep the UI's item list in sync (refetch after mutations) to avoid stale-id 404s.","Validate payloads client-side to avoid 400s.","Log non-2xx responses server-side with the reason."],"tags":["http","api","control-pane"],"backgroundTag":"http-error-response","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}