Skip to content

fix(python): accept none dimension in VectorSchema - #774

Open
HosniBelfeki wants to merge 1 commit into
alibaba:mainfrom
HosniBelfeki:fix-python-vector-schema-dimension
Open

HosniBelfeki wants to merge 1 commit into
alibaba:mainfrom
HosniBelfeki:fix-python-vector-schema-dimension

Conversation

@HosniBelfeki

@HosniBelfeki HosniBelfeki commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

What

VectorSchema declares dimension: Optional[int] = 0, and its docstring states
the value "may be None for sparse vectors"
(python/zvec/model/schema/field_schema.py:204-205, 225).

The constructor rejects it. isinstance(None, int) is False, so line 241 raises:

>>> VectorSchema("sparse", DataType.SPARSE_VECTOR_FP32, dimension=None)
ValueError: Invalid schema: vector's dimension must be >= 0

Two problems: the documented and annotated None does not work, and the error
reports a range violation for what is actually a type rejection.

Severity

Low, and not a security issue. Nothing is silently wrong and no data is
affected — a user who follows the documented sparse-vector idiom just hits a
confusing error. The repo's own fixture sidesteps it by omitting the argument
(python/tests/detail/fixture_helper.py:78), which is likely why it went unnoticed.

Fix

Normalize None to 0 before the range check. This mirrors what the same
constructor already does for its other Optional parameter, nine lines below:

Parameter Declared None handling
index_param Optional[...] = None normalized to FlatIndexParam() (line 251)
dimension (before) Optional[int] = 0 raises ValueError
dimension (after) Optional[int] = 0 normalized to 0

0 is the value sparse vector fields already carry, so this changes no existing
behavior — inputs that worked before produce identical schemas. Dense fields
declared with dimension 0 are still rejected downstream by the C++ validator
(field[...]'s dimension must be in (0,20000]), which is where the check belongs,
since 0 is legal for sparse.

Tests

  • test_dimension_none pins the documented contract. Without the fix it fails with
    ValueError: Invalid schema: vector's dimension must be >= 0; with it, the schema
    builds and dimension == 0.
  • test_dimension_invalid guards what the fix touches — -1 and "128" must still
    be rejected. It passes both with and without the change.

Verified on Linux (Debian 13 container, x86_64, CPython 3.12.14) and on Windows 11
(CPython 3.12.4). pytest python/tests/test_schema.py11 passed. Reverting the
three-line change while keeping the tests gives 1 failed, 10 passed on both
platforms, failing with the ValueError quoted above.

ruff==0.14.4 (CI's pin): ruff check .All checks passed!,
ruff format --check2 files already formatted.

VectorSchema documents `dimension` as `Optional[int] = 0` and its
docstring states the value "may be `None` for sparse vectors", but the
constructor rejects None: `isinstance(None, int)` is False, so the guard
raises "Invalid schema: vector's dimension must be >= 0" — a range error
reported for what is really a type rejection.

Normalize None to 0 before the range check, mirroring the normalization
the same constructor already applies to its other Optional parameter
(field_schema.py:251, `if index_param is None: index_param = FlatIndexParam()`).
Sparse vector fields already use dimension 0; the repo's own fixture
reaches it by omitting the argument (python/tests/detail/fixture_helper.py:78).

test_dimension_none pins the documented contract and fails without this
change with the ValueError above. test_dimension_invalid guards the
range and type rejections the fix touches, and passes both with and
without it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants