Freika/dawarich · warning · Points::VectorTileQuery::InvalidTileCoordinatesError
Invalid tile coordinates
Error message
Invalid tile coordinates
What it means
Points::VectorTileQuery raises InvalidTileCoordinatesError (message 'Invalid tile coordinates') when the zoom level z is negative or greater than 22. Inputs pass through parse_integer first (non-integer strings like 'abc' or floats like '5.5' raise the same error from Integer(value, 10)), then validate_tile_coordinates! enforces z in [0, 22]. The tiles controller rescues this error (app/controllers/api/v1/tiles/points_controller.rb:53) and answers 400, so this is a client-malformed-URL rejection, not a server fault.
Source
Thrown at app/queries/points/vector_tile_query.rb:253
def with_statement_timeout
conn = Point.connection
conn.transaction do
conn.exec_query("SET LOCAL statement_timeout = #{QUERY_TIMEOUT_MS}", 'VectorTileQuery Timeout')
yield conn
end
end
def parse_integer(value)
return value if value.is_a?(Integer)
Integer(value, 10)
rescue ArgumentError, TypeError
raise InvalidTileCoordinatesError
end
def validate_tile_coordinates!
raise InvalidTileCoordinatesError if z.negative? || z > 22
max_index = (1 << z) - 1
raise InvalidTileCoordinatesError if x.negative? || y.negative?
raise InvalidTileCoordinatesError if x > max_index || y > max_index
end
end
View on GitHub (pinned to 97fad417c5)
Solutions
- Check the requested z value in the server log - anything above 22 or below 0 is rejected by design
- Fix the style/source maxzoom to at most 22 so the client never requests z>22
- Verify the tile URL template placeholder order matches what the tiles controller parses
- Coerce z/x/y to integers client-side before building the URL
Example fix
// before
source: { tiles: ['/api/v1/tiles/points/{z}/{x}/{y}.pbf'], maxzoom: 24 }
// after
source: { tiles: ['/api/v1/tiles/points/{z}/{x}/{y}.pbf'], maxzoom: 22 } Defensive patterns
Strategy: validation
Validate before calling
function isValidTileZ(z) {
const n = Number(z)
return Number.isInteger(n) && n >= 0 && n <= 22
} Prevention
- Cap the map source's maxzoom at 22 so clients never request z>22
- Coerce z/x/y to integers before building tile URLs (fractional zooms fail parse_integer server-side)
- Keep URL template placeholder order in sync with the tiles route
When it happens
Trigger: GET of a vector tile URL like /api/v1/tiles/points/23/1/1.pbf with z=23+ (MapLibre can request zooms beyond source maxzoom if the style's maxzoom is set high or a custom URL template mangles the order of z/x/y, e.g. swapping z and x so a huge x lands in the z slot), negative z from a computed Math.floor bug, or a fractional zoom string.
Common situations: Custom URL templates with placeholders in the wrong order ({z}/{x}/{y} vs the params the backend expects), styles declaring maxzoom above 22, camera animations that clamp tiles at fractional negative zooms, hand-testing tile endpoints with arbitrary numbers.
Related errors
- No user found
- No date range specified
- errorData.error || `Failed to ${isEdit ? "update" : "create"
- Failed to fetch points: ${response.statusText}
- Failed to create visit
AI-assisted analysis of Freika/dawarich@97fad417c5 (2026-08-21).
Data as JSON: /api/errors/67d975b384c39e4e.
Report an issue: GitHub.