Skip to content

Regression: no way to write a registered third-party array encoding via VortexWriteOptions #9646

Description

@connortsui20

What happened?

VortexWriteOptions takes the file's array encoding allowlist entirely from the session's enabled editions, so an application cannot write an array encoding it registered itself. Registration and reads are unaffected.

The gate is new_array_context (vortex-file/src/writer.rs:358), built inside write_internal and reachable from no public API. with_strategy does not replace it and WriteStrategyBuilder::with_allow_encodings cannot widen it, so an encoding outside the enabled editions fails at vortex-array/src/serde.rs:196 with Array encoding app.identity not permitted by ctx.

Refusing to serialize a component outside the selected editions is intended, tested, and published in docs/specs/editions.md. The regression is the loss of the opt-out that #8855 and #8945 both documented as supported. #8946 made that opt-out unreachable while hardening the policy against replacement strategies, and #9364 later rewrote the docs to match the code. Nothing in #8946's description or review discussion mentions third-party or custom encodings.

The documented opt-out, before and after #8946

#8855 introduced editions as documentation only, ahead of any code:

You can also opt out of editions entirely to write custom or experimental encodings. Doing so is an explicit choice that gives up the standardization guarantee, only readers that know your encodings can read those files.

#8945 restated it in mechanical terms, one PR before the writer gate landed:

Lower-level sessions without an enabled-editions store opt out of editions entirely and can write custom or experimental encodings. A raw with_allow_encodings writer policy is another explicit opt-out.

#8946 made both halves false. A session with no EnabledEditions variable permits nothing rather than everything, which is why that PR had to add enable_all_registered_array_encodings to the lower-level test sessions in vortex-file, vortex-layout and vortex-parquet-variant. with_allow_encodings can only narrow, because the array context is resolved independently of it.

#9364 deleted the paragraph and replaced it with the current text:

Sessions created without the Vortex facade must register and enable their editions before writing files. The lower-level with_allow_encodings policy can further restrict array encodings, but cannot permit an encoding excluded by the selected editions.

Steps to reproduce

Details

vortex/tests/third_party_encoding.rs on claude/vortex-editions-third-party-0f81bv registers a minimal app.identity encoding on a default session and records what the writer does with it. All six cases pass as written, so the tests that assert a failure are the ones a fix must flip.

Case Result
Already-encoded custom array, default strategy normalized away before serialization, write succeeds with the encoding absent
Already-encoded custom array, leaf-only strategy fails at serde.rs:196
Replacement write strategy fails at serde.rs:196
Strategy allowlist widened to the whole array registry fails at serde.rs:196
Own edition family declared and enabled writes and round-trips
Frozen core2026.08.1 widened by declare_inclusion writes and round-trips

Restoring the pre-#8946 registry-derived allowlist on develop, with nothing else changed, flips custom_encoding_is_rejected_when_it_is_in_no_edition and with_allow_encodings_cannot_readmit_a_third_party_encoding to succeeding writes. That isolates new_array_context as the cause.

Environment

develop as of 42a5d3b.

Additional context

The workaround is for the application to declare and enable its own edition family, the way vortex-spatial and vortex-json do. That path works and independent families coexist without coordination, but it is documented nowhere an application author will look. docs/specs/editions.md presents families as a first-party mechanism, docs/developer-guide/extending/writing-an-encoding.md is a two-line stub, and docs/developer-guide/language-bindings.md still advertises Tier 3 plugins with Rust already at Tier 3 and no mention of editions.

Proposal: add an explicit per-write opt-in on VortexWriteOptions, for example with_additional_encodings(HashSet<ArrayId>), unioned into both the strategy allowlist and new_array_context. That keeps #8946's actual goal, since a replacement strategy still cannot widen anything on its own. If the project would rather not reopen the opt-out, the fix is documentation only, and the requirement belongs where plugin authors hit it.

Three related defects turned up while tracing this, each worth a separate fix:

  • declare_inclusion has no freeze check, so an application can add its encoding to frozen core2026.08.1 and write a file that presents as an edition whose published minimum reader is 0.84.0 but that no released reader can decode. EditionSession::validate does not catch it, and core_2026_08_1_encoding_set_is_pinned builds a first-party-only session, so it does not either.
  • A custom BtrBlocks scheme dropped by retain_allowed_encodings, and an already-encoded custom array normalized away by the default pipeline, both produce a successful write with the caller's encoding absent and no diagnostic. A caller who explicitly configured a scheme arguably deserves an error rather than a warning.
  • VortexWriteOptions::new snapshots the editions for the strategy while write_internal re-resolves them for the array context. The comment at writer.rs:227 states that encodings registered in between are still eligible, but they are eligible to the context and not to the default validator, so one of the two comments is wrong.

Metadata

Metadata

Labels

bugA bug issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions