Bug: KeyError: 'highway' crashes plot() when Overpass returns partial/empty data
Describe the bug
prettymaps.plot() crashes with KeyError: 'highway' when the Overpass API returns a partial or empty response (throttling, rate-limit, network timeout). This is the primary blocker that prevents rendering maps for many cities.
To reproduce
import prettymaps
prettymaps.plot("Paris, France", radius=1200)
# → Fetching geodataframes took 123.25 seconds
# → KeyError: 'highway'
Reproduced on 2026-08-19 with overpass-api.de under throttling. Zurich also fails at radius 900, 1200, and 1440.
Expected behavior
The function should either skip the empty layer and render the remaining data, or raise a meaningful error explaining that the OSM fetch returned no data for a required layer.
Root cause
fetch.py — unified_osm_request (~line 672):
When iterating layers, the code indexes all_features[key] without checking the column exists:
filtered_features = all_features[~pd.isna(all_features[key])] # KeyError if 'highway' column absent
The bare except Exception as e: catches this and returns GeoDataFrame(geometry=[]) — an empty GDF with no columns at all.
draw.py — graph_to_shapely (line 201):
Then unconditionally accesses the missing column:
gdf["width"] = gdf["highway"].map(highway_to_width) # KeyError: 'highway'
Suggested fix
draw.py — guard at top of graph_to_shapely:
if len(gdf) == 0 or "highway" not in gdf.columns:
return MultiLineString([]) # empty geometry → layer silently skipped
fetch.py — in the except branch, preserve schema so downstream code doesn't crash:
empty = GeoDataFrame(geometry=[])
layer_tags = layers_dict.get(layer, {}).get("tags", {})
for key in layer_tags.keys():
if key not in empty.columns:
empty[key] = None
gdfs[layer] = empty
Environment
- prettymaps v1.4.2
- Python 3.10.18 (Homebrew)
- macOS 15, ARM64
- osmnx 1.2.2, geopandas, matplotlib (Agg backend)
Bug:
KeyError: 'highway'crashesplot()when Overpass returns partial/empty dataDescribe the bug
prettymaps.plot()crashes withKeyError: 'highway'when the Overpass API returns a partial or empty response (throttling, rate-limit, network timeout). This is the primary blocker that prevents rendering maps for many cities.To reproduce
Reproduced on 2026-08-19 with
overpass-api.deunder throttling. Zurich also fails at radius 900, 1200, and 1440.Expected behavior
The function should either skip the empty layer and render the remaining data, or raise a meaningful error explaining that the OSM fetch returned no data for a required layer.
Root cause
fetch.py —
unified_osm_request(~line 672):When iterating layers, the code indexes
all_features[key]without checking the column exists:The bare
except Exception as e:catches this and returnsGeoDataFrame(geometry=[])— an empty GDF with no columns at all.draw.py —
graph_to_shapely(line 201):Then unconditionally accesses the missing column:
Suggested fix
draw.py — guard at top of
graph_to_shapely:fetch.py — in the except branch, preserve schema so downstream code doesn't crash:
Environment