This is an enhancement, not a bug report. cng-convert-to-parquet currently copies string
attribute values faithfully, which is correct behavior. This proposes an opt-in normalization
to defuse a recurring, silent data-quality hazard at the one layer where it can be fixed uniformly.
Motivating case (verified upstream, faithfully preserved)
WDPA NO_TAKE stores the fully-no-take category as 'All ' — with a trailing space — in the
source WDPA_Jun2026_Public.gdb itself (verified with ogrinfo over the raw GDB: 857 rows, all
five category counts match the converted parquet exactly). The conversion is faithful; the tool
is not at fault.
The consequence for consumers is severe and silent: WHERE NO_TAKE = 'All' returns zero rows —
i.e. "there are no fully no-take MPAs" — the entire global no-take marine estate made invisible by
one trailing byte. A declared values array of ["All", ...] also mismatches the ingested 'All '.
(Downstream tracking: boettiger-lab/data-workflows#511, #542.)
This is not WDPA-specific. Leading/trailing whitespace on categorical string fields is a common
upstream quirk across GDB/Shapefile sources, and every occurrence breaks equality filters the same
silent way. Fixing it per-dataset in each catalog recipe re-implements the same transform N times
and is easy to forget — which is exactly what happened here.
Proposed interface
An opt-in flag on cng-convert-to-parquet (and the corresponding workflow plumbing):
cng-convert-to-parquet <src> <dst.parquet> --layer <L> --trim-strings
--trim-strings (default off): apply trim() (strip leading/trailing whitespace) to every
VARCHAR/text column during conversion. Off by default so existing outputs are unchanged and no
data is silently mutated without the operator asking.
- Implementation is a one-line-per-column transform in the convert SQL (
trim(col) AS col for
string columns), so it composes with the existing _cng_fid synthesis and geometry handling.
Open questions for maintainers:
- Whether to also offer collapsing internal runs of whitespace (probably no — leading/trailing
is the empirically-damaging case; interior whitespace is usually meaningful).
- Whether a future default-on is acceptable, or whether opt-in is the permanent contract. I'd lean
opt-in permanently: auto-mutating attribute values on every convert is its own surprise.
Why not just fix it downstream
A downstream recipe trim (or an S3-only STAC note declaring 'All ') only patches one dataset and,
for a rolling monthly collection like WDPA, is undone at the next ingest unless re-applied every
time. A convert-layer flag makes the fix declarative and durable per recipe, and available to every
future import for free.
This is an enhancement, not a bug report.
cng-convert-to-parquetcurrently copies stringattribute values faithfully, which is correct behavior. This proposes an opt-in normalization
to defuse a recurring, silent data-quality hazard at the one layer where it can be fixed uniformly.
Motivating case (verified upstream, faithfully preserved)
WDPA
NO_TAKEstores the fully-no-take category as'All '— with a trailing space — in thesource
WDPA_Jun2026_Public.gdbitself (verified withogrinfoover the raw GDB: 857 rows, allfive category counts match the converted parquet exactly). The conversion is faithful; the tool
is not at fault.
The consequence for consumers is severe and silent:
WHERE NO_TAKE = 'All'returns zero rows —i.e. "there are no fully no-take MPAs" — the entire global no-take marine estate made invisible by
one trailing byte. A declared
valuesarray of["All", ...]also mismatches the ingested'All '.(Downstream tracking: boettiger-lab/data-workflows#511, #542.)
This is not WDPA-specific. Leading/trailing whitespace on categorical string fields is a common
upstream quirk across GDB/Shapefile sources, and every occurrence breaks equality filters the same
silent way. Fixing it per-dataset in each catalog recipe re-implements the same transform N times
and is easy to forget — which is exactly what happened here.
Proposed interface
An opt-in flag on
cng-convert-to-parquet(and the correspondingworkflowplumbing):--trim-strings(default off): applytrim()(strip leading/trailing whitespace) to everyVARCHAR/text column during conversion. Off by default so existing outputs are unchanged and no
data is silently mutated without the operator asking.
trim(col) AS colforstring columns), so it composes with the existing
_cng_fidsynthesis and geometry handling.Open questions for maintainers:
is the empirically-damaging case; interior whitespace is usually meaningful).
opt-in permanently: auto-mutating attribute values on every convert is its own surprise.
Why not just fix it downstream
A downstream recipe trim (or an S3-only STAC note declaring
'All ') only patches one dataset and,for a rolling monthly collection like WDPA, is undone at the next ingest unless re-applied every
time. A convert-layer flag makes the fix declarative and durable per recipe, and available to every
future import for free.