Skip to content

to_geotiff(cog=True, tiled=False) writes a non-COG strip TIFF #2312

@brendancol

Description

@brendancol

Describe the bug

to_geotiff(..., cog=True, tiled=False) returns successfully and writes a strip-layout TIFF. The COG spec requires a tiled internal layout, so the output is not a valid Cloud Optimized GeoTIFF even though the caller asked for one with cog=True.

The writer currently warns that tile_size is ignored under tiled=False, then writes strips via xrspatial/geotiff/_writer.py:477. The cog=True kwarg is silently dropped for the layout decision while the rest of the COG path (overviews, IFD ordering, etc.) still runs, so the file is a malformed hybrid.

This violates the stable COG contract that #2300 (commit 5e8bf9a) promoted.

To Reproduce

import numpy as np
import xarray as xr
from xrspatial.geotiff import to_geotiff

da = xr.DataArray(np.zeros((256, 256), dtype=np.float32), dims=('y', 'x'))
to_geotiff(da, '/tmp/bad.tif', cog=True, tiled=False)
# Succeeds; produces a non-COG strip TIFF labelled as COG by intent.

Expected behavior

cog=True combined with tiled=False should raise ValueError at the public boundary with a message that names the violated constraint and tells the caller to either pass tiled=True or drop cog=True.

Fix shape

  1. Reject the combination in xrspatial/geotiff/_writers/eager.py next to the existing validation block. Match the error-message style from PR Pin actionable failure modes for unsupported COG writer inputs (#2286 prod-ready wave B) #2301 / commit f5fbad5.
  2. Defense in depth: raise from xrspatial/geotiff/_writer.py near line 477 if cog and not tiled ever reaches that path. This guards against future callers that bypass the public boundary.
  3. Remove the now-dead "warn that tile_size is ignored when tiled=False under cog=True" branch. Under the new gate, cog=True implies tiled=True, so the warning would never fire on a cog=True call.
  4. Add regression tests: one for the rejection (with message-substring matching, like the rows in test_cog_invalid_input_errors_2286.py), and one smoke test confirming the tiled COG path still works.

Additional context

Related PRs:

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions