bevyengine/bevy · error · GltfError

unsupported primitive mode

Error message

unsupported primitive mode

What it means

Bevy's GltfLoader only maps five of glTF's eight primitive modes to a wgpu PrimitiveTopology: Points, Lines, LineStrip, Triangles, TriangleStrip (crates/bevy_gltf/src/loader/gltf_ext/mesh.rs:21-29). Loading a mesh primitive that uses Mode::LineLoop (mode 2) or Mode::TriangleFan (mode 6) returns UnsupportedPrimitive { mode } from primitive_topology(), called during primitive loading at loader/mod.rs:766. A triangle fan is always expressible as a triangle list by rewiring the index buffer, so this is a data problem, not a Bevy limitation in principle.

Source

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

        material::{
            alpha_mode, material_label, needs_tangents, uv_channel,
            warn_on_differing_texture_transforms,
        },
        mesh::{primitive_name, primitive_topology},
        scene::{node_name, node_transform},
        texture::{texture_sampler, texture_transform_to_affine2},
    },
};
use crate::convert_coordinates::GltfConvertCoordinates;

/// Must match [`MAX_JOINTS`](https://docs.rs/bevy/latest/bevy/pbr/constant.MAX_JOINTS.html)
pub const MAX_JOINTS: usize = 256;

/// An error that occurs when loading a glTF file.
#[derive(Error, Debug)]
pub enum GltfError {
    /// Unsupported primitive mode.
    #[error("unsupported primitive mode")]
    UnsupportedPrimitive {
        /// The primitive mode.
        mode: Mode,
    },
    /// Invalid glTF file.
    #[error("invalid glTF file: {0}")]
    Gltf(#[from] gltf::Error),
    /// Binary blob is missing.
    #[error("binary blob is missing")]
    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}")]

View on GitHub (pinned to 396ca72708)

Solutions

  1. Re-export the model from your DCC with a glTF 2.0 exporter (Blender's glTF exporter triangulates fans/loops into lists/strips by default).
  2. If you control the pipeline, preprocess the file: rewrite TRIANGLE_FAN indices into TRIANGLE_LIST order and set "mode": 4.
  3. If the geometry is decorative, strip the offending primitive or convert the mesh to lines/points in a 3D tool.
  4. As a last resort, implement a custom loader (fork or GltfLoader extension) that performs the fan-to-list conversion.

Example fix

// scene.gltf (before)
"primitives": [{ "mode": 6, "indices": 0 }]  // TRIANGLE_FAN
// after: fan converted to list by the exporter
"primitives": [{ "mode": 4, "indices": 1 }]  // TRIANGLES
Defensive patterns

Strategy: validation

Validate before calling

fn has_unsupported_primitives(path: &std::path::Path) -> bool {
    let (doc, _blob, _) = gltf::import(path).unwrap();
    doc.meshes()
        .flat_map(|m| m.primitives())
        .any(|p| !is_supported_mode(p.mode()))
}

Type guard

fn is_supported_mode(mode: gltf::mesh::Mode) -> bool {
    use gltf::mesh::Mode::*;
    matches!(mode, Points | Lines | LineStrip | Triangles | TriangleStrip)
}

Try / catch

match err {
    GltfError::UnsupportedPrimitive { mode } => {
        warn!("skipping mesh primitive, glTF mode {mode:?} not supported");
    }
    other => return Err(other.into()),
}

Prevention

When it happens

Trigger: A .gltf/.glb whose mesh primitive JSON contains "mode": 2 (LINE_LOOP) or "mode": 6 (TRIANGLE_FAN); any file loaded via asset_server.load(...gltf) or GltfLoader::load that reaches primitive_topology(primitive.mode()) and matches the catch-all arm.

Common situations: Legacy CAD/DCC exporters (old 3ds Max, some FBX-to-glTF converters, assimp with fan preservation), hand-authored glTF JSON, or models converted from OpenGL-era tutorials that used GL_TRIANGLE_FAN/GL_LINE_LOOP.

Related errors


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