{"record":{"id":"7248e0bd4c25efe5","repo":"pbakaus/impeccable","slug":"impeccable-annotation-upload-failed","errorCode":null,"errorMessage":"[impeccable] annotation upload failed:","messagePattern":"\\[impeccable\\] annotation upload failed:","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"skill/scripts/live-browser.js","lineNumber":8064,"sourceCode":"    // Only upload + forward the screenshot when annotations (comments/strokes)\n    // are present. Without annotations the image is pure visual anchoring -\n    // it biases the model toward the current rendering and works against the\n    // three-distinct-directions brief.\n    if (blob && hasAnnotations) {\n      try {\n        const uploadRes = await fetch(\n          'http://localhost:' + PORT + '/annotation?token=' + encodeURIComponent(TOKEN) +\n          '&eventId=' + encodeURIComponent(basePayload.id),\n          { method: 'POST', headers: { 'Content-Type': 'image/png' }, body: blob },\n        );\n        if (uploadRes.ok) {\n          const { path: p } = await uploadRes.json();\n          screenshotPath = p;\n        } else {\n          console.warn('[impeccable] annotation upload failed:', uploadRes.status);\n        }\n      } catch (err) {\n        console.warn('[impeccable] annotation upload failed:', err);\n      }\n    }\n    // Annotated requests must wait for capture + upload because the screenshot\n    // is semantic input. Plain requests were already dispatched above.\n    if (hasAnnotations) {\n      basePayload.clientSentAt = Date.now();\n      sendEvent(screenshotPath ? { ...basePayload, screenshotPath } : basePayload);\n    }\n  }\n\n  //\n  // Shader overlay - renders the captured screenshot as a WebGL texture and\n  // runs an editorial \"ink-wash\" fragment shader over it during generation.\n  // A single rolling band sweeps top-to-bottom, desaturating + tinting kinpaku\n  // and leaving a soft trail. Makes the wait feel like a letterpress scan\n  // instead of a dead spinner.\n  //\n","sourceCodeStart":8046,"sourceCodeEnd":8082,"githubUrl":"https://github.com/pbakaus/impeccable/blob/f88b2837a7d7c3182e46307bbbb091a1ed547571/skill/scripts/live-browser.js#L8046-L8082","documentation":"When a generate/steer request carries annotations, the captured PNG is POSTed to /annotation?token=...&eventId=... on the live server, and the returned path is attached to the event as screenshotPath. A non-2xx response status or a fetch rejection is logged as 'annotation upload failed:' (with the status code or error); the event is then still sent, just without the annotated image, so the model loses the semantic input but not the request.","triggerScenarios":"Server restarted so the embedded TOKEN is stale (401); an older server build without the /annotation route (404); blob too large or server died mid-upload (network error); wrong PORT after a restart.","commonSituations":"Server restart between page load and annotation; version skew between injected client and server; uploading a very large annotated screenshot on a constrained machine.","solutions":["Check the logged status: 401 → reload the page for a fresh token; 404 → update the live server to a version with /annotation","Resend the annotated request once the server is reachable and the token fresh","Keep annotations modest in size (crop strokes, not full-page) to avoid payload limits"],"exampleFix":"// before\nif (uploadRes.ok) { /* ... */ } else { console.warn('annotation upload failed:', uploadRes.status); }\n// after: one token-refresh retry on auth failure\nif (uploadRes.status === 401) { await refreshToken(); uploadRes = await fetch(url, init); }","handlingStrategy":"retry","validationCode":"if (!blob?.size) throw new Error('nothing to upload'); // skip upload for empty captures\nconst uploadUrl = `/annotation?token=${encodeURIComponent(TOKEN)}&eventId=${encodeURIComponent(basePayload.id)}`;","typeGuard":null,"tryCatchPattern":"try {\n  let res = await fetch(uploadUrl, { method: 'POST', headers: { 'Content-Type': 'image/png' }, body: blob });\n  if (res.status === 401) { TOKEN = await refreshToken(); res = await fetch(uploadUrl, { method: 'POST', body: blob }); }\n  if (!res.ok) console.warn('annotation upload failed:', res.status);\n} catch (err) { console.warn('annotation upload failed:', err); } // always send the event afterwards","preventionTips":["Refresh the token after server restarts before uploading","Keep annotated screenshots compact (crop to the element)","Log the numeric status — 401 vs 404 vs network tells you exactly which fix applies"],"tags":["upload","annotation","dev-server","http-status","screenshot"],"backgroundTag":"upload-request-failed","analyzedSha":"f88b2837a7d7c3182e46307bbbb091a1ed547571","analyzedAt":"2026-08-18T04:58:36.608Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}