Skip to content

Troubleshooting

Messages below are quoted from mapcv. Use your browser’s find (Ctrl/⌘+F) with a few words of your error.

mapcv lists every invalid field at once, then exits with code 1:

Config error in bad1.yaml:
• region: region.west must be less than region.east
• imagery.source: the built-in 'google_satellite' source was removed in mapcv 0.2.0: Google does not
permit downloading its imagery for datasets (see MIGRATION.md and PROVIDERS.md)
• labels.path: labels.path must be a .geojson, .json, .kml, .gpkg, .shp, .parquet or .geoparquet file,
got 'buildings.kmz' (a KMZ is a zipped KML: unzip it and use the .kml inside)
Fix the fields above, or start from a working config with mapcv init.
Message Fix
Config file not found: … Check the path, or create one with mapcv init
Config error in …: not valid YAML at line 4, column 3 (…) A YAML syntax error: usually indentation, a missing colon or space after it, or an unclosed bracket or quote, at or just before that line
Config error in …: it holds no settings The file is empty, or not a mapping of keys (region:, imagery:, …). Start from mapcv init
Not a config file: … is a folder. Pass the YAML file, not its folder
imagery.type is required: 'xyz', 'geotiff', 'eopf_zarr' or 'stac_cog' Add type: to the imagery block
region.west must be less than region.east (or south/north) Coordinates are swapped. The order is west, south, east, north in degrees
the built-in 'google_satellite' source was removed … Google’s terms do not allow it. Choose another source (Migrating to 0.2)
the built-in 'osm' source was removed … OSM’s tile servers forbid bulk downloads. Use a commercial or self-hosted OSM tile service via url_template, or use OSM data as labels (Prepare labels)
unknown tile source '…'; built-in sources: … Typo in source, or use url_template
imagery: provide either 'source', 'url_template' or 'earth_engine' Add one of them
imagery: set 'source' or 'url_template', not both Keep only one of them
sampler.stide: Extra inputs are not permitted An unknown key, usually a typo (here stride) or an option from a different mapcv version. Fix or remove the field named before the colon
url_template must contain {x}, {y} and {z}; missing … Add the placeholders
url_template has unsupported placeholder(s) {s} (replace {s} with one subdomain, e.g. 'a') Write e.g. https://a.tile.example.com/{z}/{x}/{y}.png
EOPF Zarr imagery requires writer.image_format='npy' (or 'tif') Set writer.image_format: npy (or tif for georeferenced GeoTIFF patches)
XYZ imagery supports writer.image_format 'png', 'jpg' or 'tif' npy is for Sentinel-2 and GeoTIFF imagery
labels.classes requires labels.label_field Name the property that holds the class
labels.classes['…'] must be an integer in 1..255 IDs are mask values; 0 is background
imagery.path must not contain credentials, query strings, or fragments; … Only local or anonymous public products are supported. Download private products first
`tiles:` was replaced by `imagery:` in mapcv 0.2 and removed in 0.3; … Move the old tiles block under imagery: {type: xyz, zoom: …, source: …} and delete region.zoom
`region.zoom` was moved to `imagery.zoom` in mapcv 0.2 and removed in 0.3; … Delete region.zoom and set imagery.zoom
Input should be 'spatial', 'stratified', 'random' or 'region' Typo in split.strategy or --strategy
split.strategy: region holds out whole areas of interest, which come from region.path; … Set region.path to a file of area polygons, or use another strategy
imagery.path … is a folder; to read the GeoTIFFs in it as one mosaic, use a pattern such as …/*.tif Give a glob pattern, not the folder
writer.world_files adds .pgw/.jgw files to PNG and JPG patches and …, so with image_format '…' it would write none; remove it Remove world_files: GeoTIFF patches carry their georeferencing

The tiles: and region.zoom errors mean a 0.1 config: both layouts were removed in 0.3.0. See Migrating.

Unknown keys are errors, reported with their full path:

Config error in unknown.yaml:
• imagery: imagery: set 'source' or 'url_template', not both
• sampler.stide: Extra inputs are not permitted
Fix the fields above, or start from a working config with mapcv init.

Label file or output folder not where you expect. Relative paths in the config are resolved against the config file’s folder, not the directory you run mapcv from. mapcv validate prints the resolved paths.

⚠ no label polygon intersects the region, so every mask would be background. (from plan) or … intersects the imagery extent, so every mask will be background. (from generate) The polygons don’t overlap the region. Usually longitude and latitude are swapped in the file ([52.37, 4.94] instead of [4.94, 52.37]) or in the region, the file is in a projected CRS without a crs member, or the region is elsewhere. Open the file in QGIS or geojson.io.

⚠ no usable label polygon in labels.geojson, so every mask would be background. (from plan; generate says the same about “the label file”) The file has no feature mapcv can use: it is empty, its features are all of a skipped type (points or lines for segmentation), or no feature has a label_field value listed in classes (the warnings above it count what was skipped). For a GeoPackage with several layers, check labels.layer.

GeoJSON: skipped 1 without polygon geometry (points/lines), 1 without a label value. Some features were not used. Points and lines can’t be rasterized as areas; features with an empty label_field value are skipped; with labels.classes, unlisted values are skipped too. If all features are skipped, check the spelling of label_field: mapcv plan shows 0 polygons.

labels.label_field '…' has N distinct values; masks support at most 255 classes. You picked an ID-like field (for example osm_id). Choose a category field, or map values with labels.classes.

GeoJSON 'crs' … is not supported; mapcv reads GeoJSON as WGS-84 longitude/latitude (RFC 7946). Re-export the file in EPSG:4326 (ogr2ogr -t_srs EPSG:4326).

Expected FeatureCollection or Feature, got: … The file is not GeoJSON features (for example a bare geometry). Wrap it in a Feature.

Overpass request to … failed: …. The public server limits load; try again later or set labels.osm.overpass_url to another instance (labels.osm) The Overpass server refused the request, closed the connection before the whole answer arrived, or sent something that is not valid HTTP. The public servers are shared and drop requests when busy: run the command again later, ask for a smaller region or fewer classes, or point labels.osm.overpass_url at another instance. Nothing is cached from a failed request.

Unexpected class IDs. Labels like 0, 1, 2 are numbered in sorted order (1, 2, 3) because 0 is not a valid class ID. Pin IDs with labels.classes. See How class IDs are chosen.

Generation failed: Too many failed tiles: 2/2 (100.0% exceeds 5.0% threshold): 2 x HTTP 503 (e.g. …). If the provider is busy or rate-limiting, try again later or lower imagery.max_connections; raise imagery.max_failed_ratio to accept gaps. More than max_failed_ratio of a chunk’s tiles failed under policy: lenient. Look at one tile URL in a browser. Check the zoom (many servers have no tiles above 19), your key and quota, and max_connections. Then re-run: finished chunks are kept.

HTTP 404 Not Found for URL: … (with policy: strict) The server has no tile there: wrong zoom, wrong {x}/{y} order in url_template, or the area is outside its coverage. 403/401 mean a missing or invalid key.

Response for … is not an image (23867 bytes); the server may be returning an error page or rate-limiting The server answered with HTML or JSON. Common causes: rate limiting, a consent or login page, an expired key, or a template that points at a web page rather than a tile endpoint.

XYZ tile sources must return 256x256 RGB-compatible images The server sends 512 px (“retina”) tiles. Use its 256 px endpoint, or remove an @2x / {r} marker from the URL. The message names the tile and its size. A tile that fails like this is not kept in the tile cache, so a corrected server or URL works on the next run.

The tile server is not answering: the first 8 requests all failed (…) Timeouts, refused connections or HTTP 429/5xx for every request so far. mapcv stops instead of trying every tile. Check the URL, your network and your quota, or try later.

response too large A tile body over 4 MiB: the server is not sending map tiles at that URL.

⚠ 2 of 2 tiles failed; check the tile URL, your network and imagery.policy … More than half of the requested tiles failed, but the run finished (usually policy: ignore). The dataset is mostly black: fix the URL or network and generate into a new folder.

Black patches. Under lenient or ignore, failed tiles become black, and their mask pixels hold labels.ignore_index (255 by default). A patch whose tiles all failed has no imagery at all and is left out (generate says how many); one that is only partly black is kept. Set sampler.max_empty_ratio (for example 0.1) to drop mostly-black patches too. Some providers also serve black or “no imagery” placeholder tiles at high zooms, which are not failures: lower the zoom if many are affected.

Too slow / rate limited. Lower max_connections. mapcv already retries with backoff and honours Retry-After.

Redirect refused for …: the tile server redirected to another host (…); mapcv follows redirects of a url_template with a query string only within its own host. Put the final tile URL in imagery.url_template The server sends its tiles from somewhere else. A template with a query string (where keys usually are) is only followed on its own host, so the key goes nowhere else. Open one tile URL in a browser, then use the address it ends up at. Redirects from https to plain http, or from a public server to this machine or a private network, are refused too.

Cannot resume: … was generated with a different configuration (labels); use a new writer.staging_dir or remove the old dataset The folder already holds a dataset built with other settings (the fields in brackets): for example labels after editing the label file, writer after switching between png and jpg, patch_shape, sampler after changing the patch size. Point writer.staging_dir at a new folder or undo the change. Details: What must stay the same.

… is a version-1 manifest from mapcv 0.1.x and cannot be resumed Generate into a new folder. mapcv split and mapcv info still read the old one. A dataset made by mapcv 0.2 with sampler.mode: random cannot be resumed either, and a 0.2 dataset resumes only with labels.ignore_index: null (and, for JPEG patches, writer.jpg_subsampling: "4:4:4"); the message says which. See Datasets made by mapcv 0.2.

… manifest version N was written by a newer mapcv; upgrade mapcv to read it The dataset was made with a newer release. Upgrade with pip install -U mapcv.

… manifest.json cannot be read (…). It may be incomplete or edited by hand: restore it, or generate the dataset again into a new folder The manifest is truncated or was edited. Restore it from a copy, or generate again into a new folder.

This config would write no patches. (plan and generate, exit code 1) The plan holds no patch: the region is smaller than one sampler.patch_size, or edge_strategy: drop leaves none. Enlarge the region, lower patch_size or set edge_strategy: pad. If a run that did start ends with No patches were written., every patch was dropped by sampler.max_empty_ratio or min_label_ratio; no dataset is left in the folder.

This config cannot be built: the grid has 8,960 x 5,888 = 52,756,480 patches, more than the limit of 3,000,000 for one run (plan and generate, exit code 1; sampler.random_count asks for … patches for random mode) The sampler settings give more patches than one run can hold. Raise sampler.stride (a stride of 1 gives a patch at every pixel), use a larger patch_size, shrink the region or split it into several smaller ones, one config each.

patch_size: true is a YAML boolean, not a number YAML reads yes, on and true as booleans. Write the number itself.

This is a large job. Re-run with --yes to confirm. (exit code 2) You ran a job over 20,000 tiles, 5 GB or 1,000,000 patches without a terminal. Read the plan, then pass --yes.

Generation failed: permission denied: … mapcv can’t create or write files in writer.staging_dir (or the folder named). Make it writable, or point writer.staging_dir at a folder you own, then run the same command again.

Generation failed: no space left on the disk: … The disk filled up while writing patches. Free some space, or set writer.staging_dir to another disk and start there; on the same disk, run the same command again and it resumes.

Interrupted. Finished chunks are saved; run the same command again to resume. (exit code 130) You pressed Ctrl-C. Nothing is lost but the chunk in progress.

Unsafe link: … is a link to …, outside … mapcv does not read or write through links that leave the folder (from generate, split, stats, card, verify and export) A symbolic link in the dataset folder points outside it, so a write (or an export) would reach a file elsewhere. A dataset copied or unpacked from somewhere else can hold such links. Replace the link with the file itself, or use another folder. Links that stay inside the folder are fine.

… manifest.json cannot be read (patch file '…' is not a path inside the dataset folder; …) The manifest names a patch file by an absolute path or one with .., which mapcv never writes: the manifest was edited. Restore it from where the dataset came from, or generate it again.

No manifest found at …/manifest.json (from info, split, stats, card, verify and export) The folder is not a dataset: pass the folder mapcv generate wrote, the config’s writer.staging_dir.

Earth Engine imagery needs the gee extra: pip install "mapcv[gee]" Install it: pip install "mapcv[gee]".

Earth Engine could not render '…': … Log in once with earthengine authenticate … Earth Engine refused the request. Run earthengine authenticate once, set imagery.earth_engine.project to a Cloud project registered for Earth Engine, and check the asset ID in the Earth Engine catalog. Earth Engine’s own message follows the asset name.

EOPF Zarr support is optional; install it with 'pip install mapcv[zarr]'. Install the extra: pip install "mapcv[zarr]".

Sentinel-2 (EOPF Zarr) support needs Python 3.10-3.13: … You are on Python 3.14, where the zarr extra installs nothing because zarr 2’s numcodecs has no Python 3.14 wheels. Create a Python 3.13 environment for Sentinel-2 (for example uv venv --python 3.13).

EOPF Zarr product not found: … The local path does not exist. Remote products must be https:// or s3:// URLs.

requested region does not intersect the EOPF product The region is outside the product’s footprint. Each product covers one ~110 km MGRS tile; pick a product whose footprint contains your region.

EOPF variables not found: b10. Available variables: … Band names are b01–b12 and b8a; L2A has no b10.

Unable to open anonymous EOPF product '…': … The URL is wrong, not public, or the server is unreachable. Copy the product link again from the EOPF STAC browser and make sure it ends in .zarr (the product, not one of its assets).

Unable to open anonymous EOPF product '…': open_group() got an unexpected keyword argument 'zarr_format' The environment has xarray 2026.9 or newer, which needs zarr 3, next to the zarr 2 that xarray-eopf requires. pip install "mapcv[zarr]" keeps xarray below 2026.9; in an existing environment run pip install "xarray<2026.9".

Generation failed: reading rows 0-1024 failed 4 times; last error: … A read from the remote product failed (for example a time-out) four times in a row. Run the same command again: finished chunks are kept.

band b02 returned no data for rows … while other bands did; the read probably failed (e.g. a network timeout). A band came back empty where the other bands have data, which usually means a failed remote read. mapcv stops instead of writing broken patches; run the same command again to resume from that chunk.

Long pause after the plan. Opening a remote product reads its metadata over the network and can take a few minutes; an “Opening imagery…” spinner (in a log, an Opening imagery… line) shows while it does. The progress bar starts once reading begins.

Many patches skipped. Swath edges and no-data areas are NaN, and a pixel counts as valid only when every selected band has data; with max_empty_ratio: 0.2, patches more than 20 % empty are dropped. Move the region inside the footprint or choose another product.

Garbled boxes in CI logs. Output to a file or a pipe has no colours and no progress bar (a plain line per tenth of the chunks instead). Panels and tables still wrap at 80 columns there: set a wide COLUMNS (for example COLUMNS=120) for unwrapped logs, and add -q to drop the progress lines too.

Errors missing from a redirected log. Errors go to stderr, so mapcv generate x.yaml > log.txt leaves them on the terminal. Use > log.txt 2>&1 to keep both in the file.

Run the failing command again with --debug before the command name, for example mapcv --debug generate mapcv.yaml. It prints the full traceback after the error and mapcv’s debug log: which imagery was opened, each chunk’s size and timing, tile cache hits, failed tiles and their causes, and why a resume was refused. --debug-log run.log writes the same to a file. Credentials in the config’s URLs (keys in a query string, user information, the path of a tile template) are hidden in both, including in the errors of an invalid config.

Then open an issue with the output of mapcv doctor (or mapcv doctor --json; it prints no secrets), mapcv validate <config> (it hides URLs and keys) and the --debug output or log file. Tile URLs show only their host there; remove any other API keys from anything you paste.