kitao/pyxel · error

No embedded tileset in file '{path}'

Error message

No embedded tileset in file '{path}'

What it means

The TMX contains a tileset, but its `columns` attribute is absent (the Tileset struct models `@columns` as Option<u32>). The parser needs the column count to compute tile (x, y) coordinates via id % columns and id / columns, so it refuses to proceed. In practice this means the tileset is not an embedded tileset with image data — e.g. it is an external or image-collection tileset without a columns attribute.

Source

Thrown at crates/pyxel-core/src/tmx_parser.rs:71

    // Load and validate the TMX layer.
    let mut file = File::open(path).map_err(|_| err("Failed to open file"))?;
    let mut tmx_text = String::new();
    file.read_to_string(&mut tmx_text)
        .map_err(|_| err("Failed to read file"))?;

    let tmx: TmxMap = serde_xml_rs::from_str(&tmx_text).map_err(|_| err("Failed to parse file"))?;

    if tmx.tilewidth != TILE_SIZE || tmx.tileheight != TILE_SIZE {
        return Err(err("Invalid tile size in file"));
    }

    let tileset = tmx
        .tilesets
        .first()
        .ok_or_else(|| err("No tileset found in file"))?;
    let columns = tileset
        .columns
        .ok_or_else(|| err("No embedded tileset in file"))?;

    let layer = tmx
        .layers
        .get(layer_index as usize)
        .ok_or_else(|| format!("Layer {layer_index} not found in file '{path}'"))?;
    if layer.data.encoding != "csv" {
        return Err(err("Unsupported encoding in file"));
    }

    let tile_ids: Vec<u32> = remove_whitespace(&layer.data.tiles)
        .split(',')
        .map(|s| s.parse::<u32>().map_err(|_| err("Failed to parse file")))
        .collect::<Result<_, _>>()?;

    // Convert TMX global tile IDs into Pyxel image tile coordinates.
    let tilemap = Tilemap::try_new(layer.width, layer.height, ImageSource::Index(0))
        .map_err(|_| err("Layer dimensions are too large in file"))?;
    let mut tilemap_ref = rc_mut!(tilemap);

View on GitHub (pinned to 50f9bd7778)

Solutions

  1. Embed the tileset in the .tmx so Tiled writes the `columns` attribute (Tileset > Embed in map)
  2. Add columns="N" to the <tileset> element, matching the tileset image width divided by tile width
  3. If using an image-collection tileset, convert it to a single-image tileset that has a columns count
  4. Pre-process the XML to inject the columns attribute before parsing

Example fix

// before
<tileset firstgid="1" name="tiles" tilewidth="16" tileheight="16" tilecount="64"/>
// after (128px-wide sheet / 16px tiles = 8 columns)
<tileset firstgid="1" name="tiles" tilewidth="16" tileheight="16" tilecount="64" columns="8"/>
Defensive patterns

Strategy: validation

Validate before calling

fn tileset_has_columns(tmx_path: &str) -> std::io::Result<bool> {
    let xml = std::fs::read_to_string(tmx_path)?;
    let has_ts = xml.contains("<tileset");
    let has_cols = xml.split("<tileset").skip(1)
        .next().map(|s| s.contains("columns="))
        .unwrap_or(false);
    Ok(has_ts && has_cols)
}

Prevention

When it happens

Trigger: parse_tmx encounters `<tileset firstgid="1" ...>` with no `columns` attribute, which is typical of external .tsx-referenced tilesets or image-collection tilesets, where the attribute only exists on embedded image-based tilesets.

Common situations: Using Tiled's image collection tilesets; exporting a map that references a .tsx file instead of embedding the tileset; manually trimming attributes from the tileset element; older tooling that omits optional attributes.

Related errors


AI-assisted analysis of kitao/pyxel@50f9bd7778 (2026-09-03). Data as JSON: /api/errors/456fa19b5615f6a8. Report an issue: GitHub.