{"record":{"id":"55dd255eacbfa721","repo":"zed-industries/zed","slug":"canvas-text-raster-returned-bytes-expected-byte-count","errorCode":null,"errorMessage":"Canvas text raster returned {} bytes, expected {byte_count}","messagePattern":"Canvas text raster returned (.+?) bytes, expected (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/gpui_web/src/canvas_text.rs","lineNumber":178,"sourceCode":"        }\n        canvas.configure(css_font)?;\n        canvas\n            .context\n            .clear_rect(0.0, 0.0, f64::from(width), f64::from(height));\n        canvas\n            .context\n            .fill_text(\n                text,\n                -f64::from(bounds.origin.x.0) + f64::from(subpixel_offset.0),\n                -f64::from(bounds.origin.y.0) + f64::from(subpixel_offset.1),\n            )\n            .map_err(|error| anyhow!(\"drawing Canvas text: {error:?}\"))?;\n        let image = canvas\n            .context\n            .get_image_data(0.0, 0.0, f64::from(width), f64::from(height))\n            .map_err(|error| anyhow!(\"reading Canvas text raster pixels: {error:?}\"))?;\n        let mut pixels = image.data().0;\n        ensure!(\n            pixels.len() == byte_count,\n            \"Canvas text raster returned {} bytes, expected {byte_count}\",\n            pixels.len()\n        );\n        if color {\n            for pixel in pixels.chunks_exact_mut(4) {\n                pixel.swap(0, 2);\n            }\n            Ok(pixels)\n        } else {\n            let mut alpha = Vec::new();\n            alpha\n                .try_reserve_exact(pixel_count)\n                .context(\"allocating Canvas text alpha mask\")?;\n            alpha.extend(pixels.chunks_exact(4).map(|pixel| pixel[3]));\n            Ok(alpha)\n        }\n    })","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/zed-industries/zed/blob/916fc2b8cb3a815cbef4a3b40e13081be72036b6/crates/gpui_web/src/canvas_text.rs#L160-L196","documentation":"After drawing text, `rasterize` reads back the canvas with get_image_data and verifies the returned pixel buffer length equals the expected byte_count (width * height * 4 bytes RGBA). This error is thrown when the browser returned a different number of bytes than requested. Since the canvas is resized to exactly width x height before drawing, a mismatch indicates a browser/implementation inconsistency rather than caller error.","triggerScenarios":"The OffscreenCanvas 2D backend returns an ImageData whose size does not match the get_image_data request — e.g. the canvas resize (set_width/set_height) silently failed or was clamped by the browser (browsers cap canvas size, returning a smaller buffer), or a buggy WebView implementation of OffscreenCanvas getImageData.","commonSituations":"Browsers or embedded WebViews that silently clamp canvas dimensions below the requested size (some cap total canvas area or max dimension independently); memory-constrained environments where the resize failed; non-conformant OffscreenCanvas implementations in older runtimes.","solutions":["Verify the browser's own canvas size limits (check canvas.width/canvas.height after resize); reduce the raster size below the browser's cap.","Update the browser/WebView runtime; older OffscreenCanvas implementations have getImageData bugs.","Retry the rasterize with smaller bounds if the runtime silently clamped the canvas.","If persistent, log actual vs expected sizes and report the runtime; work around by tiling the raster."],"exampleFix":"// before\nlet image = ctx.get_image_data(0.0, 0.0, width as f64, height as f64)?;\n// after (caller-side guard)\nlet width = width.min(max_supported_canvas_dimension(&runtime));\nlet height = height.min(max_supported_canvas_dimension(&runtime));\nrasterize(text, font, bounds_with_size(width, height), offset, color)?;","handlingStrategy":"try-catch","validationCode":"let pixels = (width as usize) * (height as usize) * 4;\n// No caller-side pre-check can fully prevent this; the mismatch is browser-side.","typeGuard":null,"tryCatchPattern":"match rasterize(text, font, bounds, offset, color) {\n    Ok(pixels) => upload_to_atlas(pixels),\n    Err(err) if err.to_string().contains(\"returned\") && err.to_string().contains(\"bytes\") => {\n        log::warn!(\"canvas readback size mismatch: {err}; retrying with smaller bounds\");\n        retry_with_tiled_bounds(text, font, bounds, offset, color)\n    }\n    Err(err) => return Err(err),\n}","preventionTips":["Keep rasters well below the browser's own canvas dimension caps.","Target up-to-date browser/WebView runtimes with conformant OffscreenCanvas.","Treat this error as an environment problem: fall back to tiled/smaller rasters rather than crashing."],"tags":["canvas","text-rasterization","wasm","browser-compatibility"],"backgroundTag":"unexpected-response-shape","analyzedSha":"916fc2b8cb3a815cbef4a3b40e13081be72036b6","analyzedAt":"2026-09-19T19:09:50.599Z","contentChangedAt":"2026-09-19T19:09:50.599Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}