Repository navigation
docs(error-catalog): INVALID_FIELD names the refusal of a search over an empty resolved search set - #24353
Conversation
… an empty resolved search set The engine refuses a non-blank `search` with `400 INVALID_FIELD` (`param: 'search'`) when the object's resolved search set is empty, instead of answering every row. The catalog's Cause text listed every other read axis that answers this code but not this one. One sentence is added after the `internal: true` sentence, with the two remedies the refusal message itself prescribes. Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp Co-authored-by: Claude <noreply@anthropic.com>
席位核对ACCEPT · Form. Draft, base Scope. 1 file, +4 / −0, inside the The sentence, clause by clause, against the code on
Gates, pinned to head Accepted deviation, with a correction to this PR's body. The Verification section says "Six commands first refused with exit 3" and "all six exited 0". The dev's report corrects it: five commands first refused because packages were not built — four exited 3 ( Out of scope. The Acceptance notes name four sibling pages that describe the data read route's Landing. Ready, then auto-merge through the queue, by this seat. Generated by Claude Code |
Fixes #24331
Clause-②: no
What
One sentence is added to the Cause text of
### INVALID_FIELDincontent/docs/api/error-catalog.mdx, right after theinternal: truesentence. It names the refusal that PR #24320 (ec749fbb44) added. When an object's resolved search set is empty, a non-blanksearchgets400 INVALID_FIELDwithparam: 'search'. It no longer gets every row back. The sentence also gives the two remedies the refusal message itself prescribes. No other entry changes and no section is added. The diff is +4 / -0 lines, all inside that entry.Read from the code, not from the card
The wording comes from the producer as it stands on the base
33f700b87b. No commit betweenec749fbb44and the base touchespackages/objectql/src/engine.tsorpackages/objectql/src/search-filter.ts: thegit logover that range and those paths is empty.git merge-base --is-ancestor ec749fbb44 33f700b87bexits 0.ObjectQL.expandSearchOnAstinpackages/objectql/src/engine.ts. WhenexpandSearchToFilterreturnsnulland the normalized term is non-blank, it throwsemptySearchSetError(...).find,findOne,countandaggregateall reach this call.status: 400,code: 'INVALID_FIELD',object,param: 'search'. This matches the card.resolveSearchFieldResolutioninpackages/spec/src/data/search-fields.tsruns over the object's fields after theinternal: trueones are removed. AsearchableFieldsentry counts only when it names an existing field that is not aformula. If no entry does, the auto-default is used, and the refusal fires only when the auto-default is empty too. The auto-default skips hidden fields, the system names inSEARCH_AUTO_EXCLUDED_FIELDS(id,created_at,owner_id, and others), and every type outside the textual set plusselect.searchableFieldsentry naming one". The code differs in two ways. Some textual fields do not count: a hidden one, a system-named one, or one markedinternal: true. And a declared entry may name any stored field, such as alookuporjsoncolumn, not only a textual one. So the sentence says "the default search scans none" and "internal: truefields never count", not "no textual or enum stored field".searchableFieldson the object naming a stored field, or mirror the composed title onto a stored text field and search that. The card's remedies match the message. The sentence keeps both. It says "a composed title" because the catalog sets up no junction object for "the" to refer to.Verification
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived the commands from the tree atd87f5a77f, the head of this PR. The change set is 1 path and the list has 41 commands, the same list as the dispatch-time reading.PREREQUISITE NOT MET) because packages were not built. Five needed the@objectstack/lintclosure:check:doc-formula-expressions,check:doc-security-posture, speccheck:docs,check:docs-transcript-driftand speccheck:skill-examples. The client SDK case ofcheck:skill-examplesalso needed the client packages built.scripts/pm/os-verify-lock.sh. The@objectstack/lint...build was 4/4 tasks, all cache hits. The@objectstack/client-react...plus@objectstack/client...build was 35/35 tasks, 34 of them cache hits. The six commands were then re-run, and all six exited 0.--ranreconciliation printed:41 derived, 41 run, 0 NOT-MEASURED, 0 UNRUN.@mdx-js/mdx3.1.1 (exit 0), and the new sentence appears once in the output.Build Docs,Test Coreand the type-check lanes. The derivation lists these as CI-only.skip-changeset).origin/mainhas moved todd72a047f, which touches only.claude/skills/pm-dispatch/**. That is disjoint from this diff, so main was not merged in.Acceptance notes
These other hand-written pages describe how
searchbehaves on the data read route, and none of them mentions this refusal. They are left unchanged here because they are outside this card's file surface:content/docs/protocol/kernel/error-handling.mdx:626: says the catalog'sINVALID_FIELDentry "enumerates every read axis this one code answers on". Its list in parentheses namesselect,expand,searchFields,groupByandaggregations[].field, but notsearch.content/docs/api/data-api.mdx:26: thesearchparameter row. Alsocontent/docs/api/data-api.mdx:153-158: a table ofsearch/searchFieldsrequests and their results, with no row for a bare?search=on an object that has no searchable field.content/docs/data-modeling/queries.mdx:476(the Full-Text Search section) andcontent/docs/protocol/objectql/query-syntax.mdx:1120: both describe how search fields are resolved and howsearchFieldsis refused, but not this refusal.Generated by Claude Code