gt-jdbc-mysql pushes lon-lat WKT to MySQL 8 SRID 4326 (expects lat-lon), causing "Latitude out of range" on WMS spatial filters

Environment

  • GeoServer 2.28.x, gt-jdbc-mysql 34.4, JTS 1.20.0, JDK 21
  • MySQL 8.0 (tested with stock Connector/J 9.6.0)
  • Layer: native geometry SRID 4326 column, declared SRS EPSG:4326, projection policy FORCE_DECLARED

Problem

A WMS GetMap request against a MySQL 8 table whose geometry column is declared SRID 4326 fails with:

  com.mysql.cj.jdbc.exceptions.MysqlDataTruncation:
  Data truncation: Latitude 119.475 is out of range in ST_GeomFromText.

The WKT pushed down is longitude-latitude (JTS internal order), but MySQL 8’s geographic SRS 4326 is defined as AXIS["Lat",NORTH], AXIS["Lon",EAST] and
validates the first ordinate against [-90,90], so the longitude value is rejected as a latitude.

Reproducing DDL / data

  CREATE TABLE g (
    id int primary key,
    geom geometry SRID 4326
  );
  -- stored as lat-lon, as MySQL 8 SRID 4326 requires:
  INSERT INTO g VALUES (1, ST_GeomFromText(
    'POLYGON((30.2 120,30.2 120.2,30.4 120.2,30.4 120,30.2 120))', 4326));

Generated SQL (from the general log / stack trace)

  ... WHERE MBRIntersects(geom,
    ST_GeomFromText('POLYGON((119.475 29.485, ...))', 4326))
                                              -- ^^^^ lon-lat, from JTS

What I have already ruled out

  • Not the JDBC driver: it receives a fully-built SQL string via executeQuery(String) and sends it as-is; it does not parse or reorder WKT. Re-tested
    with stock mysql-connector-j 9.6.0.
  • Not the request axis order: WMS 1.1.1 (east/north) and WMS 1.3.0 (north/east, flipped by GeoServer) produce the same pushed-down lon-lat WKT. The
    request-to-internal flip happens correctly; the emitted WKT is JTS x=lon, y=lat.
  • PostGIS does not have this problem, because its geometry(4326) convention is lon-lat (it does not honor EPSG axis order), matching JTS. MySQL 8 honors
    the SRS axis order.
  • gt-jdbc-mysql 34.4 (decompiled): MySQLFilterToSQL.visitLiteralGeometry(...) calls geometry.toText() directly in both the precise and non-precise
    branches, then writes it with the current SRID — no axis swap anywhere. MySQLDialect.isMySqlVersion80OrAbove only controls ST_SRID(col,0) wrapping for the
    envelope and does not affect the WKT. There is also no data-store parameter for axis order.
  • -Dorg.geotools.referencing.forceXY=false makes MySQL accept the WKT but breaks the persisted native bounding box (resulting in WHERE 0=1), reverses
    the WFS coordinate output order, and still fails WMS 1.1.1 — so it is not a viable fix.

Questions

  1. Is this a known issue? I could not find an open GEOT ticket.
  2. Is the intended fix to flip ordinates for MySQL 8 geographic SRSes inside visitLiteralGeometry (similar to how the SQL Server / Oracle dialects handle
    their axis-aware geometry types)? I would be happy to contribute a patch if someone can confirm the right approach — flip only when isMySqlVersion80OrAbove
    and the SRID is geographic, or use an axis-order-aware WKT writer?
  3. Is there a supported workaround on the GeoServer side without changing the column SRID to 0?

Happy to provide the full stack trace and DB general log on request.

On Mon, 17 Aug 2026 at 12:56, moti <noreply@discourse.osgeo.org> wrote:

motimoti
August 17

Questions1. Is this a known issue? I could not find an open GEOT ticket.

I’ve not heard of anyone with this issue before, though I don’t know many people who use SQLServer for serious work either.

  1. Is the intended fix to flip ordinates for MySQL 8 geographic SRSes inside visitLiteralGeometry (similar to how the SQL Server / Oracle dialects handle
    their axis-aware geometry types)? I would be happy to contribute a patch if someone can confirm the right approach — flip only when isMySqlVersion80OrAbove
    and the SRID is geographic, or use an axis-order-aware WKT writer?

The problem is that epsg:4326 can mean different things to different people, read https://docs.geotools.org/stable/userguide/library/referencing/order.html for a fuller discussion of the problem. But if 4326 always means lat, lon then modifying the SQLServer code to do that (carefully, checking what the actual incoming axis order is) is probably the way to go.

  1. Is there a supported workaround on the GeoServer side without changing the column SRID to 0?

Storing your data in some other projection?

Ian

Oracle folks decided to make the WKT axis order to follow the CRS definitions in MySQL 8 https://dev.mysql.com/blog-archive/axis-order-in-spatial-reference-systems/. Probably they thought honestly that they were doing the right thing, and perhaps they did, but others did not follow. Therefore there is a continuous need to be able to handle both lon-lat and lat-lon WKT with MySQL.
The cleanest way to handle the case might be to do that on the MySQL side

ST_GeomFromText('POINT(10.3958 63.4269)', 4326, 'axis-order=long-lat')

-Jukka Rahkonen-

Hi Ian, all,

Following up on the MySQL 8 geographic SRS axis-order thread: I’ve
filed GEOT-7960 and opened PR #5836.

Ticket: https://osgeo-org.atlassian.net/browse/GEOT-7960
PR:     https://github.com/geotools/geotools/pull/5836

First, to avoid any confusion: this is the MySQL JDBC dialect
(gt-jdbc-mysql), not SQL Server.

The trigger is narrow but real: MySQL 8 + a geographic SRS such as
EPSG:4326 + precise spatial operations. MySQL 8 interprets WKT/WKB for
geographic SRS in latitude-longitude order, while GeoTools hands geometry
literals to the dialect in east/north (x=longitude, y=latitude) order.
The result is either a “Latitude … is out of range” error on filtering
or silently swapped coordinates on read/write.

I’d argue against flipping ordinates inside visitLiteralGeometry or using
an axis-order-aware WKT writer in Java. I checked the SQL Server and
Oracle dialects for precedent, and neither swaps the JTS coordinates -
both rely on the same east/north convention the other JDBC dialects
assume. Reordering the JTS geometry in Java would break that internal
convention and affect filter evaluation, rendering, and every other code
path touching the geometry.

MySQL 8 offers a cleaner, database-native lever: the
‘axis-order=long-lat’ option on ST_GeomFromText / ST_GeomFromWKB /
ST_asWKB. The PR passes that option on the geometry I/O and filter
encoder paths, gated on usePreciseSpatialOps && isMySqlVersion80OrAbove:
ST_GeomFromText/ST_GeomFromWKB on write and filter pushdown, and
ST_asWKB on read. It is a no-op for projected SRS and SRID 0 (MySQL only
reverses coordinates for geographic SRS), and MySQL 5.x paths are
unchanged because the option does not exist there. JTS coordinates are
never reordered.

On the incoming axis order (the EPSG:4326 question): filter geometries
are reprojected to the feature type’s native CRS before encoding
(ReprojectingFilterVisitor in gt-main), and the JDBC layer passes the
literal through unchanged. What reaches visitLiteralGeometry is therefore
GeoTools’ internal east/north order - the same assumption the other
dialects code against. Under the non-default forceXY=false setup that
internal convention changes, but that is a configuration the whole JDBC
dialect stack shares, not something specific to this fix.

The PR adds unit tests asserting the generated SQL carries the
axis-order option on MySQL 8 and omits it before MySQL 8, and
mvn -pl modules/plugin/jdbc/jdbc-mysql test passes. I’ve also verified
the change end-to-end against an 8.0-compatible server (WMS GetMap and
WFS BBOX filtering).

Happy to adjust based on review. Thanks for the guidance so far.

Cheers,
Mengting Wu

Hi Jukka,

Agreed - that is exactly what the patch does. It passes
‘axis-order=long-lat’ on the MySQL side, leaving the JTS geometry in
GeoTools’ internal east/north order:

\* ST_GeomFromText(..., 4326, 'axis-order=long-lat') in the filter
  encoder (visitLiteralGeometry) and in the basic WKT write path
\* ST_GeomFromWKB(?, 4326, 'axis-order=long-lat') in the prepared
  WKB write path
\* ST_asWKB(col, 'axis-order=long-lat') on the read/envelope paths

It is gated on usePreciseSpatialOps && isMySqlVersion80OrAbove, so the
5.x paths (no axis-order support, no range check) are unchanged. For
projected SRS and SRID 0 the option is a no-op because MySQL only
reverses coordinates for geographic SRS, which also matches the
behaviour you described.

Tracking in GEOT-7960; the PR is up for review at
[GEOT-7960] Fix MySQL 8 geographic SRS axis order in JDBC dialect by moti1008 · Pull Request #5836 · geotools/geotools · GitHub (unit tests cover both
the MySQL 8 and pre-8 cases).

Cheers,
Mengting Wu

Hi all,

Quick follow-up: the fix has been merged into main and backported to the

35.x and 34.x stable branches (PR #5836, GEOT-7960). It will ship in the

next point releases of GeoTools 34 and 35.

For anyone hitting this before the release: building gt-jdbc-mysql from the

34.x / 35.x branch and replacing the jar in GeoServer works around it.

Thanks for the discussion and review.

Mengting