FyroxEngine/Fyrox · warning

Failed to load brush tool data due to

Error message

Failed to load brush tool data due to: {err}

What it means

While deserializing a TileBrush's macro data, one BrushMacroData value failed to read from the region. The library logs the error and skips that value, continuing to read the remaining data, so a brush loads with potentially missing macro entries.

Solutions

  1. Re-save the brush/tile map in the current editor version to regenerate compatible data.
  2. Check the logged error text for the specific field that failed to read.
  3. Update the Fyrox version on the side that produced the resource so formats match.
  4. If data was hand-edited, restore it and edit through the editor API instead.
Defensive patterns

Strategy: try-catch

Try / catch

// the library already catches per-entry failures; react afterwards
if brush_macros.len() < expected_count {
    Log::warn("some brush macros failed to load, re-saving brush recommended");
}

Prevention

When it happens

Trigger: Loading a scene/resource containing a TileBrush whose saved macro data count does not match readable entries — e.g. a version format change or corrupted brush data.

Common situations: Opening a scene saved by a different Fyrox version with a different brush macro layout; hand-edited or corrupted brush resources.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


AI-assisted analysis of FyroxEngine/Fyrox@76c91aad8e (2026-09-10). Data as JSON: /api/errors/a222db082a41db90. Report an issue: GitHub.

Appendix: source

Thrown at fyrox-impl/src/scene/tilemap/brush.rs:146

/// Custom Visit implementation to prevent the visit from completely failing if
/// it encounters data that cannot be visited.
impl Visit for BrushMacroInstanceList {
    fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
        let mut region = visitor.enter_region(name)?;

        let mut count = self.0.len() as u32;
        count.visit("Count", &mut region)?;

        if region.is_reading() {
            self.clear();
            for i in 0..(count as usize) {
                let name = i.to_string();
                // If one value fails to read, skip it and read the remaining data.
                let mut value = BrushMacroData::default();
                match value.visit(&name, &mut region) {
                    Ok(()) => self.0.push(value),
                    Err(err) => Log::err(format!("Failed to load brush tool data due to: {err}")),
                }
            }
        } else {
            for (i, value) in self.0.iter_mut().enumerate() {
                let name = i.to_string();
                value.visit(&name, &mut region)?;
            }
        }

        Ok(())
    }
}

/// A brush can have zero or more instances of a macro, and each instance
/// has its own configuration data.
#[derive(Debug, Default, Clone, Visit, PartialEq, Reflect)]
#[reflect(type_uuid = "3aa87ac2-c05f-4e9b-86eb-ee846a364585")]
pub struct BrushMacroData {

View on GitHub (pinned to 76c91aad8e)