a-b-street/abstreet · error

Unexpected topojson contents

Error message

Unexpected topojson contents

What it means

load_all_zones_as_geojson parses a TopoJSON string and expects the TopJson::Topology variant so it can convert the "zones" object to GeoJSON; anything else (e.g. TopoJson::Geometry or a parse yielding another variant) bails with this fixed message. The tool assumes its popgetter-downloaded input is a TopoJSON Topology.

Solutions

  1. Verify the input is real TopoJSON Topology (has a "topology" type / "objects" member) before calling.
  2. Re-download the census zones from the popgetter source to replace the corrupted/mislabeled file.
  3. If the input is actually GeoJSON, use the GeoJSON code path instead of the TopoJSON parser.
  4. Check which object name is expected — the converter looks up the "zones" object; supply a Topology containing it.

Example fix

// before: passing plain GeoJSON text
let zones = load_all_zones_as_geojson(geojson_str)?;
// after: ensure TopoJSON topology
assert!(topojson_str.contains("\"type\": \"Topology\""));
let zones = load_all_zones_as_geojson(topojson_str)?;
Defensive patterns

Strategy: validation

Validate before calling

if !topojson_str.trim_start().contains("\"Topology\"") && !topojson_str.contains("\"type\":\"Topology\"") {
    return Err("input is not a TopoJSON Topology".into());
}

Type guard

fn is_topology(parsed: &TopoJson) -> bool {
    matches!(parsed, TopoJson::Topology(_))
}

Try / catch

match load_all_zones_as_geojson(s) {
    Err(e) if e == "Unexpected topojson contents" => {
        // s was likely plain GeoJSON: parse via the GeoJSON path instead
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling load_all_zones_as_geojson (popgetter/src/lib.rs:104) with a string that parses as TopoJson but is not a Topology — e.g. a plain GeoJSON file mislabeled as topojson, or a TopoJSON containing only bare geometry objects.

Common situations: Wrong download URL or cached file that is actually plain GeoJSON; file corruption truncating the Topology wrapper; API version change returning a different TopoJSON structure.

Related errors


AI-assisted analysis of a-b-street/abstreet@0964f29315 (2026-09-13). Data as JSON: /api/errors/c056a1f1eb3755de. Report an issue: GitHub.

Appendix: source

Thrown at popgetter/src/lib.rs:104

        output.len()
    );

    Ok(output)
}

fn load_all_zones_as_geojson(path: &str) -> Result<Vec<Feature>> {
    let mut start = Instant::now();
    let topojson_str = fs_err::read_to_string(path)?;
    println!("Reading file took {:?}", start.elapsed());

    start = Instant::now();
    let topo = topojson_str.parse::<TopoJson>()?;
    println!("Parsing topojson took {:?}", start.elapsed());

    start = Instant::now();
    let fc = match topo {
        TopoJson::Topology(t) => to_geojson(&t, "zones")?,
        _ => bail!("Unexpected topojson contents"),
    };
    println!("Converting to geojson took {:?}", start.elapsed());

    Ok(fc.features)
}

View on GitHub (pinned to 0964f29315)