bevyengine/bevy · error · TextureError

format requires transcoding: {0:?}

Error message

format requires transcoding: {0:?}

What it means

TextureError::FormatRequiresTranscodingError(TranscodeFormat) is an internal control-flow error produced by the KTX2/DDS format mappers when the stored format has no direct wgpu equivalent and must be transcoded: KTX2 with 8-bit sRGB single/dual channels (TranscodeFormat::R8UnormSrgb / Rg8UnormSrgb, ktx2.rs:1155-1233) or 3x8-bit samples (TranscodeFormat::Rgb8, ktx2.rs:659), and DDS R8G8B8 (dds.rs:156). Both loaders catch it immediately and transcode in place (ktx2.rs:107-109, dds.rs:30-37), so through the normal ImageLoader path it is handled, not surfaced. You only observe it by calling the mapping helpers directly (ktx2_get_texture_format / dds_format_to_texture_format) or by pattern-matching TextureError exhaustively.

Source

Thrown at crates/bevy_image/src/image.rs:2314

    /// Format requires transcoding.
    #[error("format requires transcoding: {0:?}")]
    FormatRequiresTranscodingError(TranscodeFormat),
    /// Only cubemaps with six faces are supported.
    #[error("only cubemaps with six faces are supported")]
    IncompleteCubemap,
}

/// The type of a raw image buffer.
#[derive(Debug)]
pub enum ImageType<'a> {
    /// The mime type of an image, for example `"image/png"`.
    MimeType(&'a str),
    /// The extension of an image file, for example `"png"`.
    Extension(&'a str),
    /// The direct format of the image
    Format(ImageFormat),
}

impl<'a> ImageType<'a> {
    /// Attempts to detect the appropriate [`ImageFormat`] for this image type.
    ///
    /// # Errors
    ///
    /// A [`TextureError`] will be returned if this image type is a MIME type or file extension for
    /// an unsupported or disabled format.
    pub fn to_image_format(&self) -> Result<ImageFormat, TextureError> {
        match self {
            ImageType::MimeType(mime_type) => ImageFormat::from_mime_type(mime_type)
                .ok_or_else(|| TextureError::InvalidImageMimeType(mime_type.to_string())),
            ImageType::Extension(extension) => ImageFormat::from_extension(extension)
                .ok_or_else(|| TextureError::InvalidImageExtension(extension.to_string())),
            ImageType::Format(format) => Ok(*format),
        }
    }
}

View on GitHub (pinned to 221e52ae32)

Solutions

  1. Prefer the public entry points (Image::from_buffer / ImageLoader) — they transcode automatically and this error never escapes.
  2. If you call the mappers directly, handle FormatRequiresTranscodingError like the loaders do: map R8UnormSrgb->R8Unorm, Rg8UnormSrgb->Rg8Unorm, Rgb8->Rgba8(UnormSrgb).
  3. Re-export the texture as RGBA8 KTX2/DDS so no transcoding is needed at load time.

Example fix

// before — calling the mapper directly on an RGB8 KTX2
let fmt = ktx2_get_texture_format(&ktx2, true)?; // Err(FormatRequiresTranscodingError(Rgb8))

// after — mirror the loader's fallback
let fmt = match ktx2_get_texture_format(&ktx2, true) {
    Ok(f) => f,
    Err(TextureError::FormatRequiresTranscodingError(TranscodeFormat::Rgb8)) => {
        TextureFormat::Rgba8UnormSrgb // loader transcodes RGB8 into this
    }
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: try-catch

Try / catch

let fmt = match probe_format(&ktx2) {
    Ok(f) => f,
    Err(TextureError::FormatRequiresTranscodingError(tf)) => {
        // mirror ktx2_buffer_to_image: pick the transcoded target
        match tf {
            TranscodeFormat::R8UnormSrgb => TextureFormat::R8Unorm,
            TranscodeFormat::Rg8UnormSrgb => TextureFormat::Rg8Unorm,
            TranscodeFormat::Rgb8 => TextureFormat::Rgba8UnormSrgb,
        }
    }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: Directly calling ktx2_get_texture_format on a KTX2 whose samples are 3x8-bit RGB, or dds_format_to_texture_format on an R8G8B8 DDS; loading such files normally does NOT surface it because ktx2_buffer_to_image and dds_buffer_to_image intercept the variant and transcode (gamma-fix R/RG channels or expand RGB to RGBA).

Common situations: Custom tooling built on bevy_image internals that inspects KTX2 formats; matching on TextureError and wondering why this arm fires; textures exported from tools that default to RGB8 storage (e.g. plain PPM-style KTX2 conversions).

Related errors


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