design: validate-on-serialise turns some bundles' metadata routes into 500s — escape hatch, or not?
Split out of #9 (closed), where it was raised alongside an unrelated performance bug and would have got lost.
The report
Porting cpt-sdmx-api from sdmxlib 0.48 to sdmxlib-rest 0.5.0 (sdmxlib 0.63), the 2021 CSIP census bundle carries content that sdmxlib 0.62's validate-on-serialise rejects:
- MetadataStructure attributes with no
ConceptIdentity - Metadataflows with no targets
- a MetadataSet with version
1.0, which SDMX-JSON metadata rejects because it requires semver
So the /metadata/* routes and the JSON / 3.0 metadataflow and
metadatastructure listings now return 500. #9 (closed) suggested two options: the
producer emits valid content (the right fix, already being looked at), or a
library switch — e.g. RestSettings(validate_on_serialise=...) passed through to
sl.serialize(validate=...) — as a migration escape hatch.
Framing worth getting right
This is not a regression in this library or in sdmxlib. It is the same class of problem sdmxlib-rest's own 0.2.0 port found in its test fixture: components with no ConceptIdentity, a MetadataSet naming its MSD rather than its flow with no target, and a non-semantic version. 0.48 wrote that content without complaint; 0.62 stopped letting it through. What changed is that invalid content became visible, not that valid content stopped working.
The switch would be technically trivial — to_json already takes validate= —
which is exactly why it is worth deciding on purpose rather than by default.
The case against a global switch
- It moves the failure rather than fixing it. Strict SDMX clients reject these documents too. Turning validation off swaps our 500 for a parse failure in the client, which is harder to diagnose and does not show up in our logs.
- It is too broad. The semver rule is SDMX 3.0 / JSON only;
1.0is a valid version in 2.1 XML. A global switch turns validation off for every format, including the ones where this content is perfectly valid. - Escape hatches tend to stay. A switch added for a migration is rarely removed, and keeps the producer defect invisible after it is no longer needed.
Options, roughly in the order I'd reach for them
- The producer emits valid content. The real fix; already in progress.
- Make the 500 say which artefact failed and which rule it broke. Today it is an opaque failure. Naming the artefact URN and the validation rule is cheap, catalog-agnostic, makes no content decision on anyone's behalf, and directly speeds up option 1. Worth doing regardless of the rest.
- Skip and log invalid artefacts in listings, so one bad MetadataSet does not take down a listing of fifty valid ones. Better than a global switch, but it silently drops data from a response, so it would want a header or annotation saying the listing is partial.
- A narrow switch, if one is truly needed: per-format rather than global, defaulting to validation on, and logging every artefact it lets through. Last resort.
Recommendation
Do 2 now, rely on 1, and revisit 3 or 4 only if the producer fix stalls. Not a global switch.
Open question for whoever picks this up
Which of the three failures are format-dependent? The semver one clearly is. If the missing ConceptIdentity and missing targets also only fail for some formats, the per-format switch in option 4 becomes more defensible — that should be measured, not assumed.