BabylonJS/Babylon.js · error · Error

"The shader file must end with .fragment.glsl or .block.glsl

Error message

"The shader file must end with .fragment.glsl or .block.glsl"

What it means

ExtractShaderProgramFromGlsl discovers the corresponding .vertex.glsl by replacing the fragment file's extension. It only supports files ending in .block.glsl or .fragment.glsl; any other extension makes the conversion ambiguous and throws this error.

Source

Thrown at packages/dev/smartFilters/src/utils/buildTools/convertGlslIntoShaderProgram.ts:111

    /**
     * The shader program code
     */
    shaderProgramCode: string;

    /**
     * The FragmentShaderInfo
     */
    fragmentShaderInfo: FragmentShaderInfo;
} {
    // See if there is a corresponding vertex shader
    let vertexShader: string | undefined = undefined;
    let extensionToFind: string;
    if (fragmentShaderPath.endsWith(".block.glsl")) {
        extensionToFind = ".block.glsl";
    } else if (fragmentShaderPath.endsWith(".fragment.glsl")) {
        extensionToFind = ".fragment.glsl";
    } else {
        throw new Error("The shader file must end with .fragment.glsl or .block.glsl");
    }
    const vertexShaderPath = fragmentShaderPath.replace(extensionToFind, ".vertex.glsl");
    if (fs.existsSync(vertexShaderPath)) {
        vertexShader = fs.readFileSync(vertexShaderPath, "utf8");
    }
    if (vertexShader) {
        log("Found vertex shader");
    }

    // Read the fragment shader
    const fragmentShader = fs.readFileSync(fragmentShaderPath, "utf8");
    const fragmentShaderInfo = ParseFragmentShader(fragmentShader);

    // Generate the shader program code
    const functionsSection: string[] = [];
    for (const shaderFunction of fragmentShaderInfo.shaderCode.functions) {
        functionsSection.push(
            FunctionTemplate.replace(FUNCTION_NAME, shaderFunction.name)

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Rename the file to end with .block.glsl (for block shaders) or .fragment.glsl (for plain shader programs).
  2. Check the glob/loop in the build script so only *.block.glsl and *.fragment.glsl files are converted.
  3. Ensure the paired .vertex.glsl file uses the same base name.

Example fix

// before
await ConvertShader("shaders/blur.glsl", ...);
// after
await ConvertShader("shaders/blur.block.glsl", ...);
Defensive patterns

Strategy: validation

Validate before calling

if (!/\.(block|fragment)\.glsl$/.test(shaderPath)) { throw new Error(`${shaderPath} must end with .block.glsl or .fragment.glsl`); }

Type guard

const isConvertibleShader = (p: string): boolean => p.endsWith('.block.glsl') || p.endsWith('.fragment.glsl');

Try / catch

try { await ConvertShader(path, ...); } catch (e) { if (e.message.includes('must end with .fragment.glsl')) { console.error('Rename shader:', path); } else { throw e; } }

Prevention

When it happens

Trigger: Passing a shader path to ConvertShader / ExtractShaderProgramFromGlsl that ends in something other than .block.glsl or .fragment.glsl (e.g. .glsl, .frag.glsl, .fs).

Common situations: Renamed shader files; generated intermediate files fed back into the converter; typos in file extensions; build scripts globbing the wrong files.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/93fe557c446df4ad. Report an issue: GitHub.