phaserjs/phaser · error · Error

Color attachments must have the same dimensions

Error message

Color attachments must have the same dimensions

What it means

Thrown by WebGLFramebufferWrapper when creating a framebuffer with multiple color attachments where attachment[i] (i>0) has a width or height different from attachment[0]. WebGL MRT (multiple render targets) requires all color attachments to be the same dimensions, so the wrapper rejects mismatched inputs at construction.

Solutions

  1. Ensure all color attachments are created with identical width and height.
  2. Recreate/resize every attachment together on canvas resize before rebuilding the framebuffer.
  3. Allocate targets from a shared size constant.
  4. If different sizes are genuinely needed, use separate framebuffers and composite, not MRT.

Example fix

// before
new WebGLFramebufferWrapper(renderer, {
  colorAttachments: [texA, texB] // texA 1024x768, texB 512x512 -> throws
});

// after
const w = 1024, h = 768;
texB = renderer.createTexture(w, h);
new WebGLFramebufferWrapper(renderer, { colorAttachments: [texA, texB] });
Defensive patterns

Strategy: validation

Validate before calling

const w0 = colorAttachments[0].width, h0 = colorAttachments[0].height;
if (!colorAttachments.every(t => t.width === w0 && t.height === h0)) {
  throw new Error('Color attachments differ in size');
}

Type guard

function attachmentsSameSize(atts) {
  if (!atts.length) return true;
  const { width, height } = atts[0];
  return atts.every(t => t.width === width && t.height === height);
}

Prevention

When it happens

Trigger: Constructing a WebGLFramebufferWrapper with a colorAttachments array whose textures have differing .width/.height; passing a render texture and a game texture of different sizes; resizing one attachment but not the others before rebuilding the framebuffer.

Common situations: Custom multi-target render passes (e.g. G-buffer with position + normals + albedo) where textures were allocated at different sizes; compositing pipelines that mix a half-res and full-res target into one framebuffer; post-process chains where one buffer was resized on canvas resize and another was not.

Related errors


AI-assisted analysis of phaserjs/phaser@41be1e462b (2026-08-13). Data as JSON: /api/errors/4c1e8c3db0a24072. Report an issue: GitHub.

Appendix: source

Thrown at src/renderer/webgl/wrappers/WebGLFramebufferWrapper.js:142

        this.attachments = [];

        if (!this.useCanvas)
        {
            for (var i = 0; i < colorAttachments.length; i++)
            {
                this.attachments.push({
                    texture: colorAttachments[i],
                    attachmentPoint: gl.COLOR_ATTACHMENT0 + i
                });

                if (i === 0)
                {
                    this.width = colorAttachments[i].width;
                    this.height = colorAttachments[i].height;
                }
                else if (colorAttachments[i].width !== this.width || colorAttachments[i].height !== this.height)
                {
                    throw new Error('Color attachments must have the same dimensions');
                }
            }

            // Only generate depth and stencil buffers if color attachments are provided.
            // Generate a depth-stencil buffer if both are requested.
            // These must be attached after the color attachments,
            // so that the framebuffer is complete when they're attached.
            if (addDepthBuffer && addStencilBuffer)
            {
                this.attachments.push({
                    attachmentPoint: gl.DEPTH_STENCIL_ATTACHMENT,
                    internalFormat: gl.DEPTH_STENCIL
                });
            }
            else if (addDepthBuffer)
            {
                this.attachments.push({
                    attachmentPoint: gl.DEPTH_ATTACHMENT,

View on GitHub (pinned to 41be1e462b)