{"record":{"id":"32086d8aee6d30e9","repo":"bevyengine/bevy","slug":"failed-to-prepare-asset","errorCode":null,"errorMessage":"Failed to prepare asset","messagePattern":"Failed to prepare asset","errorType":"exception","errorClass":"PrepareAssetError","httpStatus":null,"severity":"warning","filePath":"crates/bevy_render/src/erased_render_asset.rs","lineNumber":22,"sourceCode":"};\nuse bevy_app::{App, Plugin, SubApp};\nuse bevy_asset::RenderAssetUsages;\nuse bevy_asset::{Asset, AssetEvent, AssetId, Assets, UntypedAssetId};\nuse bevy_ecs::{\n    prelude::{Commands, IntoScheduleConfigs, Local, MessageReader, ResMut, Resource},\n    schedule::{ScheduleConfigs, SystemSet},\n    system::{ScheduleSystem, StaticSystemParam, SystemParam, SystemParamItem, SystemState},\n    world::{FromWorld, Mut},\n};\nuse bevy_log::{debug, error};\nuse bevy_platform::collections::{HashMap, HashSet};\nuse bevy_render::render_asset::RenderAssetBytesPerFrameLimiter;\nuse core::marker::PhantomData;\nuse thiserror::Error;\n\n#[derive(Debug, Error)]\npub enum PrepareAssetError<E: Send + Sync + 'static> {\n    #[error(\"Failed to prepare asset\")]\n    RetryNextUpdate(E),\n    #[error(\"Failed to build bind group: {0}\")]\n    AsBindGroupError(AsBindGroupError),\n}\n\n/// The system set during which we extract modified assets to the render world.\n#[derive(SystemSet, Clone, PartialEq, Eq, Debug, Hash)]\npub struct AssetExtractionSystems;\n\n/// Describes how an asset gets extracted and prepared for rendering.\n///\n/// In the [`ExtractSchedule`] step the [`ErasedRenderAsset::SourceAsset`] is transferred\n/// from the \"main world\" into the \"render world\".\n///\n/// After that in the [`RenderSystems::PrepareAssets`] step the extracted asset\n/// is transformed into its GPU-representation of type [`ErasedRenderAsset`].\npub trait ErasedRenderAsset: Send + Sync + 'static {\n    /// The representation of the asset in the \"main world\".","sourceCodeStart":4,"sourceCodeEnd":40,"githubUrl":"https://github.com/bevyengine/bevy/blob/396ca727080776bd313bb892423b7d94e03b81b4/crates/bevy_render/src/erased_render_asset.rs#L4-L40","documentation":"`PrepareAssetError::RetryNextUpdate(E)` is the soft-failure variant of the render-asset pipeline: an asset's `prepare_asset` step could not complete yet (for example a dependency image has not loaded, or `AsBindGroupError::RetryNextUpdate` was returned). The prepare system catches it and queues the asset for the next update instead of failing; it is also the variant your own `RenderAsset` impls should return for transient failures. Its Display text is the string shown.","triggerScenarios":"A material or render asset being prepared while a dependency is not yet resident (texture still uploading, bind group inputs missing), causing `prepare_asset` to return `Err(PrepareAssetError::RetryNextUpdate(..))`; the engine retries next frame without logging.","commonSituations":"Startup frames before textures finish loading; custom RenderAsset impls that depend on other GPU resources; mistaking this for a hard error because the Display text says \"Failed to prepare asset\" while the engine simply retries.","solutions":["If you emit it from your own impl: ensure the underlying condition eventually clears, otherwise the asset retries every frame forever","Pre-load dependencies (images, buffers) before spawning the asset that prepares against them","For genuinely permanent failures, log or return a hard error instead of retrying indefinitely"],"exampleFix":"// before\nfn prepare(asset: Self::SourceAsset, ...) -> Result<Self::PreparedAsset, PrepareAssetError<Self>> {\n    let Some(dep) = images.get(&asset.dep) else { panic!(\"dep not loaded\") };\n    // ...\n}\n\n// after\nfn prepare(asset: Self::SourceAsset, ...) -> Result<Self::PreparedAsset, PrepareAssetError<Self>> {\n    let Some(dep) = images.get(&asset.dep) else {\n        return Err(PrepareAssetError::RetryNextUpdate(asset));\n    };\n    // ...\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// in your RenderAsset::prepare_asset implementations\nmatch result {\n    Err(PrepareAssetError::RetryNextUpdate(asset)) => {\n        return Err(PrepareAssetError::RetryNextUpdate(asset)); // engine retries next frame\n    }\n    Err(PrepareAssetError::AsBindGroupError(e)) => {\n        error!(\"bind group failed: {e}\");\n    }\n    Ok(prepared) => { /* insert */ }\n}","preventionTips":["Return RetryNextUpdate only when the blocking condition is transient","Pre-load dependent assets before spawning assets that prepare against them","Watch for assets stuck retrying every frame; that indicates a permanent failure misclassified as transient"],"tags":["bevy","render-asset","asset-loading","retry"],"backgroundTag":"render-asset-prepare-failed","analyzedSha":"396ca727080776bd313bb892423b7d94e03b81b4","analyzedAt":"2026-08-20T16:12:39.808Z","contentChangedAt":"2026-08-20T16:12:39.808Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}