{"record":{"id":"b2c172a340fd5664","repo":"Stirling-Tools/Stirling-PDF","slug":"failed-to-get-canvas-context-b2c172","errorCode":null,"errorMessage":"Failed to get canvas context","messagePattern":"Failed to get canvas context","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"frontend/editor/src/saas/services/avatarSyncService.ts","lineNumber":90,"sourceCode":"    if (!response.ok) {\n      throw new Error(\n        `Failed to download avatar: ${response.status} ${response.statusText}`,\n      );\n    }\n\n    const blob = await response.blob();\n\n    // 2. Create image bitmap\n    const img = await createImageBitmap(blob);\n\n    // 3. Create canvas and draw scaled image\n    const canvas = document.createElement(\"canvas\");\n    canvas.width = AVATAR_SIZE;\n    canvas.height = AVATAR_SIZE;\n    const ctx = canvas.getContext(\"2d\");\n\n    if (!ctx) {\n      throw new Error(\"Failed to get canvas context\");\n    }\n\n    // Draw image scaled to fit (maintains aspect ratio, centered)\n    const scale = Math.min(AVATAR_SIZE / img.width, AVATAR_SIZE / img.height);\n    const x = (AVATAR_SIZE - img.width * scale) / 2;\n    const y = (AVATAR_SIZE - img.height * scale) / 2;\n    ctx.drawImage(img, x, y, img.width * scale, img.height * scale);\n\n    // 4. Convert to PNG blob with quality optimization\n    return new Promise((resolve, reject) => {\n      canvas.toBlob(\n        (optimizedBlob) => {\n          if (!optimizedBlob) {\n            reject(new Error(\"Failed to create optimized blob\"));\n            return;\n          }\n\n          // Check file size","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/Stirling-Tools/Stirling-PDF/blob/9ef20dcab80b85041912f045e17a6aea1d08f969/frontend/editor/src/saas/services/avatarSyncService.ts#L72-L108","documentation":"Thrown by downloadAndOptimizeAvatar() when canvas.getContext('2d') returns null. The 2D rendering context can be unavailable in headless or GPU-constrained browser environments, very old browsers, or when too many canvas contexts are simultaneously allocated. The caller syncOAuthAvatar() catches this and degrades gracefully to the existing avatar.","triggerScenarios":"Browser running in headless mode without GPU acceleration; browser security/privacy settings disabling canvas (some anti-fingerprinting extensions); extremely memory-constrained environment; old browser without full Canvas 2D support.","commonSituations":"Headless browser testing (CI/CD, Puppeteer/Playwright) without GPU; user has an anti-fingerprinting extension that blocks canvas context creation; browser under extreme memory pressure.","solutions":["Detect canvas 2D support before attempting avatar optimization and skip to raw upload","Fall back to uploading the unresized blob if canvas is unavailable","Reduce concurrent canvas operations if the context limit is the cause","Test in a non-headless browser to confirm the issue is environment-specific"],"exampleFix":"// before\nconst ctx = canvas.getContext(\"2d\");\nif (!ctx) {\n  throw new Error(\"Failed to get canvas context\");\n}\n\n// after\nconst ctx = canvas.getContext(\"2d\");\nif (!ctx) {\n  console.warn(\"[Avatar Sync] Canvas 2D unavailable, uploading raw blob\");\n  return blob; // skip resize, upload original\n}","handlingStrategy":"fallback","validationCode":"// Detect canvas 2D support before attempting optimization\nfunction hasCanvas2D(): boolean {\n  try {\n    const c = document.createElement('canvas');\n    return c.getContext('2d') !== null;\n  } catch {\n    return false;\n  }\n}\nif (!hasCanvas2D()) {\n  return rawBlob; // skip resize\n}","typeGuard":null,"tryCatchPattern":"// syncOAuthAvatar already catches all errors and returns false:\n// downloadAndOptimizeAvatar throws, but the outer syncOAuthAvatar swallows it.\n// No additional catch needed if calling through syncOAuthAvatar.","preventionTips":["Detect canvas 2D support before attempting avatar optimization and fall back to raw upload","Test avatar sync in headless/CI environments where canvas may be unavailable","Never block the user on avatar optimization — always have a graceful degradation path"],"tags":["avatar","canvas","browser-compat","saas"],"backgroundTag":null,"analyzedSha":"9ef20dcab80b85041912f045e17a6aea1d08f969","analyzedAt":"2026-08-13T22:11:39.827Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}