Shapefile in the wrong place (or in the ocean): the missing .prj

Short answer: the file has no .prj, so nothing knows what its numbers mean. The .shp stores bare doubles; the .prj beside it is the only thing that says whether they are degrees or UTM metres. Without it, GDAL prints no coordinate system, QGIS prompts for a CRS, and the browser viewer assumes WGS 84 and says so — which puts a geographic file in the right place and a UTM file off the edge of the world, with the same message either way. Below: how to tell which one you have from the numbers, and the two ogr2ogr lines that fix it, which are not interchangeable.

Everything was tested on 16 September 2026 with GDAL 3.13.3 and the shapefile-viewer with its September 2026 .prj-less message, unreleased at the time of writing. The dataset is IBGE's 2022 mesh of the 27 Brazilian states in SIRGAS 2000 geographic coordinates, converted once to SIRGAS 2000 / UTM zone 23S so the same 27 polygons exist in degrees and in metres. The Shapefile guide covers the sidecar under "If the .prj is missing"; this post is the reproduction and the fix.

Three tools, three behaviours

GDAL does not guess: ogrinfo -so on the UTM layer with its .prj deleted still reports Feature Count: 27 and the metre extent, then prints Layer SRS WKT: with (unknown) on the next line. QGIS, with its default CRS setting, prompts for a CRS when you add the layer. The viewer reads the numbers as WGS 84 degrees and appends a notice to the layer's row. The notice is new — it was not yet deployed when this was written and ships before this post — but the guess is not: a zip without a .prj has always been read as degrees; what changed is that the row now tells you.

Four variants in the viewer

Each variant was dropped into the viewer and exported with Export GeoJSON; the first vertex of Acre in that export is the placement oracle, because it is the viewer's own drawn geometry projected back to degrees.

  • UTM zip with its .prj: the row reads 27 polygons, the map shows Brazil, and the export's first pair is [-68.7928173712301, -10.999569659337354]. GDAL's -t_srs EPSG:4326 for the same vertex gives [-68.792817347, -10.999569268]. The viewer's vertex is 0.0436 m from GDAL's — both treat SIRGAS 2000 → WGS 84 as a null transformation (PROJ rates it 1 m: EPSG:15894, +proj=noop), and the 4 cm is entirely the viewer's own 0.2 m drawing grid: the exported vertex in Web Mercator is an exact multiple of 0.2 m on both axes.
  • The same zip without its .prj: the row reads 27 polygons · Unknown CRS — assuming WGS 84, the basemap stays visible, and nothing is drawn where Brazil should be. The export's first pair is [-2171693.959168141, -53.911070387188786]: the exported longitude is your easting, digit for digit — the .shp stores -2171693.959168141, 8673426.088929612 for that vertex — and the latitude is an artefact of the Mercator maths, which is periodic in the northing and returned a value that looks like a real latitude in Patagonia. An easting of −2,171,693 read as degrees lands about 6,032 times around the planet to the west. The message is the only tell, because the map looks normal.
  • The same three files dropped loose, not zipped: identical to the zip — the same row, the same transparent map, a byte-identical export. That parity is also new: until the September 2026 change, loose files without a .prj were drawn as raw Web Mercator metres on a grey canvas with the basemap hidden, which put a file in degrees inside a 45 m by 39 m box beside the origin, unrecognisable and without a message.
  • The geographic file without its .prj: the row carries the same notice, and the shape is in Brazil. Its export's first pair is [-68.7928173712301, -10.999569659337354], bit for bit the pair of the untouched IBGE zip. It works, and the viewer tells you it guessed: the guess is right because degrees are what the file holds, and the message is there so a lucky guess is not mistaken for a known CRS.

How to tell which CRS a .prj-less file is in

Look at the numbers before the map. Values within ±180 and ±90 are degrees, and the viewer's guess is right. Six- or seven-digit values are projected metres, and the guess is wrong: a UTM easting inside its zone sits between 166,000 and 834,000, a southern-hemisphere northing runs up to 10,000,000 because of the false northing, and a file spanning several zones, like this one, has eastings that go negative or past a million (this layer's run from −2,839,536 to 2,201,621). Web Mercator metres reach about 20,037,508. Export-and-look is a one-step diagnosis: if the viewer says it assumed WGS 84 and the exported longitude is a six- or seven-digit number, it is your easting, and the file was projected. Then find the zone — the EPSG cheat sheet lists the codes for Brazil and Latin America.

Assign or reproject: two commands, two verbs

Assigning says what the numbers already are; reprojecting changes them. On the file whose ogrinfo -so printed (unknown) under Layer SRS WKT:, ogr2ogr -a_srs EPSG:31983 fixed.shp in.shp writes a .prj and moves nothing: ogrinfo -so on the result prints PROJCRS["SIRGAS 2000 / UTM zone 23S" ending in ID["EPSG",31983], the extent is unchanged, and the first vertex is still -2171693.95916814 8673426.08892961. Dropped into the viewer, the assigned file lands in Brazil with the row back to 27 polygons and no notice. ogr2ogr -s_srs EPSG:31983 -t_srs EPSG:4326 out.shp in.shp does the other job: -s_srs is what the missing .prj would have said, -t_srs is where you want to go, and the result's ogrinfo -so shows GEOGCRS["WGS 84" with the extent in degrees and the first vertex at -68.792817347 -10.999569268 — the source file's stored double, recovered. Assign a file already in degrees and you have lied to it; reproject with the wrong -s_srs and every vertex moves to a wrong place a .prj now vouches for. Check the code first: gdalsrsinfo -o wkt1 EPSG:31983 | grep -m1 -o '^\(GEOGCS\|PROJCS\)\["[^"]*"' prints PROJCS["SIRGAS 2000 / UTM zone 23S"; the neighbouring 31984 prints zone 24S.

If the viewer says it assumed WGS 84 and the shape is not where it should be, fix the .prj before exporting — and if you already exported, the longitude column is your easting, unchanged.

The same failure in GeoJSON

A GeoJSON with a crs member naming EPSG:31983 fails the same way in the browser: the member is not understood, the transform is skipped, and Acre's first vertex exports at [-19.5086591263066, 61.20664023081724], in the North Atlantic — the GeoJSON guide explains under "The CRS member disappeared" why the format no longer has such a member.

Test files you can use

The dataset is IBGE's 2022 state mesh, 13,717,460 bytes, SHA-256 282ec7f0f0beeeead45e6609f4ffffce161bda04cb8ee0afcad2316d1c841bcb; the directory listing prints no licence line, so credit IBGE and check the portal's terms before republishing.

To make the broken variant, project it with ogr2ogr -f "ESRI Shapefile" -t_srs EPSG:31983 -lco ENCODING=UTF-8 utm/BR_UF_2022_utm.shp BR_UF_2022.shp, then delete utm/BR_UF_2022_utm.prj and drop the other three files into the viewer, zipped or loose. The -lco ENCODING=UTF-8 is there for a reason outside this post: without it ogr2ogr writes a Latin-1 attribute table with no .cpg, and the accents in the state names break in the browser — a .cpg problem, not a .prj one.

For teams

A .prj goes missing in a chat attachment, a copied folder, an export that never wrote one — and the map that receives the file cannot ask the sender. Geodocs keeps the coordinate system with the data on a shared map, so the team draws and collects in one CRS and the question only comes up at export, when you already know the answer.

Related Articles

Navegação