FyroxEngine/Fyrox · error

Invalid brush stroke. Holes are not enabled on terrain.

Error message

Invalid brush stroke. Holes are not enabled on terrain.

What it means

Terrain::start_stroke rejects a brush stroke whose target is the hole mask when holes are not enabled on the terrain, logging this error and returning without starting the stroke. Painting holes requires the terrain's holes feature (hole-mask layer) to be initialized first.

Solutions

  1. Enable holes on the terrain before painting: call terrain.enable_holes() (or the editor's 'Enable holes' option) before using the hole brush.
  2. Switch the brush target to a non-hole target (e.g. heightmap/layer) if holes are not needed.
  3. In scripts, guard: if brush.target == BrushTarget::HoleMask && !terrain.holes_enabled() { skip or enable first }.

Example fix

// before
terrain.paint(brush_with_hole_target, ...);

// after
terrain.enable_holes();
terrain.paint(brush_with_hole_target, ...);
Defensive patterns

Strategy: validation

Validate before calling

// Guard before painting:
if brush.target == BrushTarget::HoleMask && !terrain.holes_enabled() {
    terrain.enable_holes(); // or skip painting
}
terrain.paint(brush, stroke);

Prevention

When it happens

Trigger: Calling start_stroke (via the terrain brush API) with brush.target == BrushTarget::HoleMask on a Terrain where holes_enabled is false.

Common situations: Editor users selecting the hole-paint brush on a terrain created without holes; scripted painting targeting HoleMask by default without first enabling holes on the terrain instance.

Related errors


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

Appendix: source

Thrown at fyrox-impl/src/scene/terrain/mod.rs:2260

                .iter()
                .map(|c| (c.grid_position(), c.layer_masks[layer].clone()))
                .collect(),
        };
        TerrainTextureData {
            chunk_size,
            kind,
            resources,
        }
    }
    /// Modify the given BrushStroke so that it is using the given Brush and it is modifying this terrain.
    /// The BrushStroke will now hold references to the textures of this terrain for the target of the given brush,
    /// and so the stroke should not be used with other terrains until the stroke is finished.
    /// - `brush`: The Brush containing the brush shape and painting operation to perform.
    /// - `stroke`: The BrushStroke object to be reset to start a new stroke.
    fn start_stroke(&self, brush: Brush, stroke: &mut BrushStroke) {
        let target = brush.target;
        if brush.target == BrushTarget::HoleMask && !self.holes_enabled {
            Log::err("Invalid brush stroke. Holes are not enabled on terrain.");
            return;
        }
        stroke.start_stroke(brush, self.handle(), self.texture_data(target))
    }
    /// Modify the given BrushStroke to include a stamp of its brush at the given position.
    /// The location of the stamp relative to the textures is determined based on the global position
    /// of the terrain and the size of each terrain pixel.
    /// - `position`: The position of the brush in world coordinates.
    /// - `value`: The value of the brush stroke, whose meaning depends on the brush operation.
    /// For flatten brush operations, this is the target value to flatten toward.
    /// - `stroke`: The BrushStroke object to be modified.
    fn stamp(&self, position: Vector3<f32>, value: f32, stroke: &mut BrushStroke) {
        let Some(position) = self.project(position) else {
            return;
        };
        let position = match stroke.brush().target {
            BrushTarget::HeightMap => self.local_to_height_pixel(position),
            BrushTarget::LayerMask { .. } => self.local_to_mask_pixel(position),

View on GitHub (pinned to 76c91aad8e)