bevyengine/bevy · error · GltfError

failed to load file: {0}

Error message

failed to load file: {0}

What it means

GltfError::Io (#[from] std::io::Error) covers filesystem failures while reading the glTF file bytes in GltfLoader::load (the loader reads through io::Reader), and any io::Error raised inside the gltf parse stage. Typical kinds: NotFound, PermissionDenied, UnexpectedEof.

Source

Thrown at crates/bevy_gltf/src/loader/mod.rs:138

    /// Failed to load asset from an asset path.
    #[error("failed to load asset from an asset path: {0}")]
    AssetLoadError(#[from] AssetLoadError),
    /// Missing sampler for an animation.
    #[error("Missing sampler for animation {0}")]
    #[from(ignore)]
    MissingAnimationSampler(usize),
    /// Failed to generate tangents.
    #[error("failed to generate tangents: {0}")]
    GenerateTangentsError(#[from] bevy_mesh::GenerateTangentsError),
    /// Failed to generate morph targets.
    #[error("failed to generate morph targets: {0}")]
    MorphTarget(#[from] bevy_mesh::morph::MorphBuildError),
    /// Circular children in Nodes
    #[error("GLTF model must be a tree, found cycle instead at node indices: {0:?}")]
    #[from(ignore)]
    CircularChildren(String),
    /// Failed to load a file.
    #[error("failed to load file: {0}")]
    Io(#[from] Error),
}

/// Loads glTF files with all of their data as their corresponding bevy representations.
#[derive(TypePath)]
pub struct GltfLoader {
    /// List of compressed image formats handled by the loader.
    pub supported_compressed_formats: CompressedImageFormats,
    /// Custom vertex attributes that will be recognized when loading a glTF file.
    ///
    /// Keys must be the attribute names as found in the glTF data, which must start with an underscore.
    /// See [this section of the glTF specification](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#meshes-overview)
    /// for additional details on custom attributes.
    pub custom_vertex_attributes: HashMap<Box<str>, MeshVertexAttribute>,
    /// Arc to default [`ImageSamplerDescriptor`].
    pub default_sampler: Arc<Mutex<ImageSamplerDescriptor>>,
    /// The default glTF coordinate conversion setting. This can be overridden
    /// per-load by [`GltfLoaderSettings::convert_coordinates`].

View on GitHub (pinned to 396ca72708)

Solutions

  1. Verify the exact path (and case) exists under the asset root the AssetSource was configured with.
  2. Fix permissions or sandbox rules for the asset directory.
  3. For truncated/lock issues during development, re-save the file or reload after the write completes.
  4. Retry once for transient failures (network-mounted asset sources).
Defensive patterns

Strategy: retry

Validate before calling

fn asset_readable(asset_root: &std::path::Path, rel: &str) -> std::io::Result<()> {
    let p = asset_root.join(rel.trim_start_matches('/'));
    std::fs::metadata(&p)?; // NotFound/PermissionDenied surface here, before bevy loads
    Ok(())
}

Type guard

fn is_not_found(err: &GltfError) -> bool {
    matches!(err, GltfError::Io(e) if e.kind() == std::io::ErrorKind::NotFound)
}

Try / catch

match err {
    GltfError::Io(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
        warn!("truncated read, retrying after download completes");
        retry_load();
    }
    GltfError::Io(e) => error!("glTF io error: {e}");
    other => return Err(other.into()),
}

Prevention

When it happens

Trigger: asset_server.load("models/x.gltf") where the path does not exist under an asset root; unreadable file permissions; file truncated mid-download or mid-write during hot-reload; io errors bubbling out of gltf::Gltf::from_reader.

Common situations: Wrong path or filename casing, assets not copied into the assets folder, sandboxed/managed environments denying reads, editor writing the file while the app loads it.

Related errors


AI-assisted analysis of bevyengine/bevy@396ca72708 (2026-08-20). Data as JSON: /api/errors/a31ccd3d90e8249d. Report an issue: GitHub.