Skip to content

fix: external collection query_iterator fails with fieldID(1) not found#50386

Open
xiaocai2333 wants to merge 1 commit into
milvus-io:3.0from
xiaocai2333:cherry-pick-50203-to-3.0
Open

fix: external collection query_iterator fails with fieldID(1) not found#50386
xiaocai2333 wants to merge 1 commit into
milvus-io:3.0from
xiaocai2333:cherry-pick-50203-to-3.0

Conversation

@xiaocai2333

Copy link
Copy Markdown
Contributor

Cherry-pick

pr: #50203

Cherry-pick of #50203 to the 3.0 branch.

Issue

issue: #50188

Problem

For external collections, query_iterator returns hundreds of thousands of rows and then fails with MilvusException: (code=65535, message=fieldID(1) not found). Rebuilding the iterator from the last primary-key cursor reproduces the error immediately.

Root Cause

The proxy unconditionally appends the reserved system Timestamp field (common.TimeStampField, fieldID=1) to OutputFieldsId for the iterator MVCC dedup. On the QueryNode side, FillRetrieveResultIfEmpty is invoked when a query produces a fully empty result and resolves each OutputFieldsId entry through the collection SchemaHelper. System fields are never part of the external-collection schema (whose segcore synthesizes the timestamp as a constant Int64 column via SynthesizeExternalSystemFields), so GetFieldFromID(1) fails with fieldID(1) not found. Internal collections do not hit this because segcore returns empty-but-present columns for zero-match queries.

Fix

Special-case reserved system fields (RowID / Timestamp) in FillRetrieveResultIfEmpty and emit them as empty Int64 columns — matching the non-empty retrieve path — instead of resolving them through the schema. The proxy already strips system fields via filterSystemFields, so the user-facing result is unchanged.

Test

  • go test -tags dynamic,test -gcflags="all=-N -l" ./internal/util/typeutil/ -run TestFillIfEmpty passes, including the added external-collection and RowID+Timestamp cases.

🤖 Generated with Claude Code

The proxy appends the reserved system Timestamp field (fieldID=1) to
OutputFieldsId for the iterator MVCC dedup. On the QueryNode side,
FillRetrieveResultIfEmpty is invoked when a query produces a fully empty
result and iterates OutputFieldsId to synthesize empty columns, resolving
each field id through the collection SchemaHelper.

System fields are never part of the user/collection schema, so for external
collections (whose schema has no system fields and whose segcore synthesizes
the timestamp as an Int64 column) the lookup fails with 'fieldID(1) not
found'. This surfaces when a query_iterator paginates past the last matching
row and the next batch matches zero rows, and reproduces deterministically
when the iterator is rebuilt from the last cursor.

Fix: special-case reserved system fields (RowID/Timestamp) in
FillRetrieveResultIfEmpty and emit them as empty Int64 columns, matching the
non-empty retrieve path, instead of resolving them through the schema. The
proxy already strips system fields via filterSystemFields, so the
user-facing result is unchanged.

issue: milvus-io#50188

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: cai.zhang <cai.zhang@zilliz.com>
(cherry picked from commit 38d1c1c)
@sre-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: xiaocai2333
To complete the pull request process, please assign wxyucs after the PR has been reviewed.
You can assign the PR to them by writing /assign @wxyucs in a comment when ready.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@sre-ci-robot sre-ci-robot added the size/L Denotes a PR that changes 100-499 lines. label Jun 8, 2026
@mergify mergify Bot added dco-passed DCO check passed. kind/bug Issues or changes related a bug labels Jun 8, 2026
@sre-ci-robot sre-ci-robot added the do-not-merge/need-milestone generate by v2-label-manager label Jun 8, 2026
@sre-ci-robot

Copy link
Copy Markdown
Contributor

[INFO] PR Label Summary by Default
[SUCCESS] PR #50203 merged to master

[WARNING] Milestone not set

You can set milestone by commenting:
/set-milestone
Example:
/set-milestone 2.5.0

Use /refresh-label to update related check and label manually

@sre-ci-robot

Copy link
Copy Markdown
Contributor

[ci-v2-notice]
Notice: ci-v2 system is enabled for this PR (3.0 branch).

To rerun ci-v2 checks, comment with:

  • /ci-rerun-code-check-macos // for Code Checker MacOS (GitHub Actions)
  • /ci-rerun-build-ut-cov // for ci-v2/build-ut-cov (build + unit tests)
  • /ci-rerun-e2e-amd // for ci-v2/e2e-amd (e2e tests)
  • /ci-rerun-gosdk // for ci-v2/go-sdk (Go SDK E2E tests)

If you have any questions or requests, please contact @zhikunyao.

@sre-ci-robot

Copy link
Copy Markdown
Contributor

✅ CI Loop Results 22d2bf2

Stage Result Duration Tests
✅ Build SUCCESS 24.6min -
✅ Code-Check SUCCESS 12.7min -
✅ UT-GO SUCCESS 23.2min 1012 passed
✅ UT-Integration SUCCESS 21.7min 46 passed
✅ UT-CPP-Cov SUCCESS 79.6min 7625 passed

Total: 111min | Pipeline | Artifacts

Overall Coverage: 69.3%
Diff Coverage: CPP 85.7% (2515 hit, 419 miss, 2934 measurable lines, 5416 unmeasured) | Go 100.0% (24 hit, 0 miss, 24 measurable lines, 10 unmeasured)
Diff Coverage HTML: view changed lines
Total Patch Coverage: 85.8% (2539/2958 measurable lines, 5426 unmeasured)

@mergify mergify Bot added the ci-passed label Jun 8, 2026
@xiaocai2333 xiaocai2333 added this to the 3.1 milestone Jun 9, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci-passed dco-passed DCO check passed. do-not-merge/need-milestone generate by v2-label-manager kind/bug Issues or changes related a bug size/L Denotes a PR that changes 100-499 lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants