bevyengine/bevy · error · ShaderCacheError

Pipeline could not be compiled because the following shader

Error message

Pipeline could not be compiled because the following shader could not be loaded: {0:?}

What it means

Variant of ShaderCacheError from the shader/pipeline cache. A pipeline could not be compiled because one of the shaders it references is not loaded — the AssetId given to the cache has no loaded Shader behind it. This usually means the pipeline was queued before the shader asset finished (or failed) loading.

Source

Thrown at crates/bevy_shader/src/shader_cache.rs:538

                }
            }
            _ => module_path.clone(),
        }
    }

    fn display_name(&self, module_path: &wesl::syntax::ModulePath) -> Option<String> {
        let module_path = self.canonical_path(module_path);
        let asset_id = self.module_path_to_asset_id.get(&module_path)?;
        let shader = self.shaders.get(asset_id)?;
        Some(shader.path.clone())
    }
}

/// Type of error returned by a `PipelineCache` when the creation of a GPU pipeline object failed.
#[expect(missing_docs, reason = "Enum variants are self-explanatory")]
#[derive(Error, Debug)]
pub enum ShaderCacheError {
    #[error(
        "Pipeline could not be compiled because the following shader could not be loaded: {0:?}"
    )]
    ShaderNotLoaded(AssetId<Shader>),
    #[error("Failed to process shader:\n{0}")]
    ProcessShaderError(String),
    #[error("Shader import not yet available.")]
    ShaderImportNotYetAvailable,
    #[error("Could not create shader module: {0}")]
    CreateShaderModule(String),
}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_cache() -> ShaderCache<String, ()> {
        ShaderCache::new((), |_, source, _| match source {
            ShaderCacheSource::Wgsl(wgsl) => Ok(wgsl),

View on GitHub (pinned to 227d3a6c66)

Solutions

  1. Hold strong handles to all shaders the pipeline needs until the pipeline is created
  2. Wait for LoadState::Loaded on the shader handle (e.g. recursively_dependencies_loaded) before queueing the pipeline
  3. Check the failed-loads channel to confirm the shader path actually resolves on disk

Example fix

// before
let shader = server.load_untyped("shader.wesl");
queue_pipeline(shader.id()); // ShaderNotLoaded

// after
let shader: Handle<Shader> = server.load("shader.wesl");
if server.load_state(&shader) == LoadState::Loaded {
    queue_pipeline(shader);
}
Defensive patterns

Strategy: validation

Validate before calling

if server.load_state(&shader_handle) != bevy::asset::LoadState::Loaded {
    // defer pipeline creation until the shader is loaded
    return;
}

Try / catch

match pipeline_result {
    Err(ShaderCacheError::ShaderNotLoaded(id)) => {
        // re-queue the pipeline once the asset id reports Loaded
    }
    _ => {}
}

Prevention

When it happens

Trigger: Creating/queueing a pipeline whose ShaderPatches or shader AssetIds were derived from weak/unloaded handles, or after the shader asset failed to load; the cache looks up the shader by id, finds nothing, and returns ShaderNotLoaded(id).

Common situations: Custom render pipelines initialized during plugin build before the asset server loads shaders; hot-reload evicting a shader; typos in shader asset paths so the load never completes.

Related errors


AI-assisted analysis of bevyengine/bevy@227d3a6c66 (2026-08-20). Data as JSON: /api/errors/253dd4461d3936c9. Report an issue: GitHub.