bevyengine/bevy · error · GltfError

invalid image uri: {0}. asset path error={1}

Error message

invalid image uri: {0}. asset path error={1}

What it means

Raised at loader/mod.rs:1261-1263 when a texture's source is a plain URI (not a data:) and LoadContext::resolve_embed_str(uri) fails, producing InvalidImageUri(uri, ParseAssetPathError). Like buffers, image URIs must resolve to a child path of the glTF asset; absolute URLs/paths or malformed relative references fail here.

Source

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

    MissingBlob,
    /// Decoding the base64 mesh data failed.
    #[error("failed to decode base64 mesh data")]
    Base64Decode(#[from] base64::DecodeError),
    /// Unsupported buffer format.
    #[error("unsupported buffer format")]
    BufferFormatUnsupported,
    /// The buffer URI was unable to be resolved with respect to the asset path.
    #[error("invalid buffer uri: {0}. asset path error={1}")]
    InvalidBufferUri(String, ParseAssetPathError),
    /// Invalid image mime type.
    #[error("invalid image mime type: {0}")]
    #[from(ignore)]
    InvalidImageMimeType(String),
    /// Error when loading a texture. Might be due to a disabled image file format feature.
    #[error("You may need to add the feature for the file format: {0}")]
    ImageError(#[from] TextureError),
    /// The image URI was unable to be resolved with respect to the asset path.
    #[error("invalid image uri: {0}. asset path error={1}")]
    InvalidImageUri(String, ParseAssetPathError),
    /// Failed to read bytes from an asset path.
    #[error("failed to read bytes from an asset path: {0}")]
    ReadAssetBytesError(#[from] ReadAssetBytesError),
    /// 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

View on GitHub (pinned to 396ca72708)

Solutions

  1. Download the textures and point uris at files shipped next to the model ("textures/albedo.png").
  2. Keep the exporter's directory layout untouched.
  3. Use '/' separators and relative paths.
  4. Prefer GLB with embedded textures for portable assets.

Example fix

// (before)
"images": [{ "uri": "https://cdn.example.com/albedo.png" }]
// (after)
"images": [{ "uri": "textures/albedo.png" }]
Defensive patterns

Strategy: validation

Validate before calling

fn image_uris_local(json: &serde_json::Value) -> bool {
    json["images"].as_array().unwrap_or(&vec![]).iter()
        .filter_map(|i| i["uri"].as_str())
        .filter(|u| !u.starts_with("data:"))
        .all(|u| !u.contains("://") && !u.starts_with('/'))
}

Try / catch

match err {
    GltfError::InvalidImageUri(uri, e) => {
        error!("image uri {uri} cannot resolve under the asset path ({e}); ship the texture next to the model");
    }
    other => return Err(other.into()),
}

Prevention

When it happens

Trigger: "images": [{ "uri": "https://cdn.example.com/albedo.png" }] or an absolute "/textures/albedo.png"; a relative uri that escapes the asset root; mismatched path separators.

Common situations: Web-origin models keeping CDN texture links; folders reorganized after export; textures renamed without updating the glTF JSON.

Related errors


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