{"record":{"id":"88a02c67a8fee841","repo":"BabylonJS/Babylon.js","slug":"source-channel-must-be-between-0-and-3-r-g-b-a","errorCode":null,"errorMessage":"Source channel must be between 0 and 3 (R, G, B, A)","messagePattern":"Source channel must be between 0 and 3 \\(R, G, B, A\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/dev/core/src/Materials/Textures/textureMerger.ts","lineNumber":111,"sourceCode":" * Merge multiple texture channels into a single texture\n * @param name Name for the resulting texture\n * @param config Merge configuration\n * @param scene Scene to create the texture in\n * @returns The merged texture\n */\nexport async function MergeTexturesAsync(name: string, config: ITextureMergeConfiguration, scene: Scene): Promise<ProceduralTexture> {\n    const channels = [config.red, config.green, config.blue, config.alpha];\n    const textureInputs: BaseTexture[] = [];\n    const textureInputMap: number[] = []; // Maps channel index to texture input index (-1 for constants)\n\n    // Collect unique textures and validate inputs\n    for (let channelIndex = 0; channelIndex < 4; channelIndex++) {\n        const channel = channels[channelIndex];\n        if (channel) {\n            if (IsTextureInput(channel)) {\n                // Validate source channel\n                if (channel.sourceChannel < 0 || channel.sourceChannel > 3) {\n                    throw new Error(\"Source channel must be between 0 and 3 (R, G, B, A)\");\n                }\n\n                // Find or add texture to inputs\n                let textureIndex = textureInputs.indexOf(channel.texture);\n                if (textureIndex === -1) {\n                    textureIndex = textureInputs.length;\n                    textureInputs.push(channel.texture);\n                }\n                textureInputMap[channelIndex] = textureIndex;\n            } else if (IsConstantInput(channel)) {\n                // Validate constant value\n                if (channel.value < 0 || channel.value > 1) {\n                    throw new Error(\"Constant value must be between 0.0 and 1.0\");\n                }\n                textureInputMap[channelIndex] = -1;\n            } else {\n                throw new Error(\"Invalid channel input configuration\");\n            }","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/core/src/Materials/Textures/textureMerger.ts#L93-L129","documentation":"MergeTexturesAsync combines up to four channels (R/G/B/A) from textures or constants. When a channel is a texture input, its sourceChannel selects which RGBA channel to sample and must be 0–3. This error is thrown when sourceChannel is out of range or non-integral out-of-bounds.","triggerScenarios":"Calling MergeTexturesAsync (directly or via CreateMergedAnisotropyTexture / glTF _convertMetalRoughFactorsToMetallicRoughnessAsync) with an ITextureMergerTextureInput whose sourceChannel is < 0 or > 3.","commonSituations":"Confusing sourceChannel (0–3) with the target channel index, passing -1 as a sentinel, computing the channel dynamically and going out of range, mixing up RGB index with an enum.","solutions":["Set sourceChannel to a value in 0..3 (0=R, 1=G, 2=B, 3=A).","Clamp or validate any dynamically computed channel index before calling.","If you meant to fill the channel with a fixed value, use a constant input ({ value }) instead of a texture input."],"exampleFix":"// before\n{ texture: roughTex, sourceChannel: 4 }\n// after\n{ texture: roughTex, sourceChannel: 2 } // 0=R, 1=G, 2=B, 3=A","handlingStrategy":"validation","validationCode":"function assertValidSourceChannel(ch: { texture: unknown; sourceChannel: number }): void {\n  if (!Number.isInteger(ch.sourceChannel) || ch.sourceChannel < 0 || ch.sourceChannel > 3) {\n    throw new Error(`sourceChannel must be 0-3, got ${ch.sourceChannel}`);\n  }\n}","typeGuard":"function hasValidSourceChannel(c: { sourceChannel: number }): c is { sourceChannel: 0 | 1 | 2 | 3 } {\n  return c.sourceChannel === 0 || c.sourceChannel === 1 || c.sourceChannel === 2 || c.sourceChannel === 3;\n}","tryCatchPattern":"try {\n  const tex = await MergeTexturesAsync(inputs, width, height, scene);\n} catch (e) {\n  if (String(e.message).includes(\"Source channel must be between 0 and 3\")) {\n    console.error(\"Fix channel config: 0=R 1=G 2=B 3=A\");\n  }\n}","preventionTips":["Type sourceChannel as 0|1|2|3 union in your config types.","Never use -1 as a sentinel in texture inputs; omit the channel or use a constant input."],"tags":["texture-merger","validation","channel-index"],"backgroundTag":"invalid-channel-index","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}