You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
storage: the presigned-upload door answers 500 INTERNAL for a non-numeric size and accepts a negative size #27413
QA-source: #27409 · attachments-storage.presigned-upload-roundtrip · observed beside the clauses
Found by an off-clause probe (size boundary values) in the 18.3.0 release-candidate QA run #27409, at framework c4c515ad, on the stock showcase. Signed in through the form.
Reproduction
As admin, POST /api/v1/storage/upload/presigned with {"filename":"a.png","mimeType":"image/png","size":"abc"}. It answers 500 INTERNAL, and the server log reads Insert operation failed sys_file "Size (bytes) must be a number".
The same request with "size": -5 answers 200, and a pending sys_file row is stored with size: -5.
Expected vs actual
Expected: 400 INVALID_REQUEST for a size that is not a non-negative finite number, with no row written. A 500 tells an operator the server is broken when the client sent a bad value.
Actual: 500 for "abc", and 200 with a negative-size row for -5.
Mechanism
packages/services/service-storage/src/storage-routes.ts (around lines 916 to 930) checks only size == null, then calls requireWithinUploadLimit(Number(size)). That lets NaN and negative values through.
For NaN, the engine's field validation throws at insert, and the route's catch maps that to 500.
For a negative value, nothing refuses it.
Suggested acceptance
"abc", -5, NaN, and "" each answer 400 naming size, and no sys_file row is written.
Read fresh. The presigned-upload door answers 500 for a non-numeric size and stores a negative one. A bad input should get a 400 with no row written. As it stands, the door stores wrong data and points operators at the server, so p2.
⛔ Use the door's own refusal envelope (ADR-0112): 400, with the field named.
It is extracted from the 18.3.0 RC run, so it is listed in wave anchor [sweep] v18.3.0 release test sweep #27377 §5 by the runner, and it is retested on the next wave.
Triage: lands in packages/services/service-storage/src/storage-routes.ts (domain:server); rationale: this concurs with the first touch at 06:02Z (comment 6489280043). Labels stay as they are (bug, priority:p2, pm:queue, area:files, domain:server). This note adds the parts of the first touch that the duties require and that were missing. Read at origin/main ded67bfb, 2026-10-29T09:55Z.
Class (a): a reproducible defect, with reach measured on the public REST presign door. A negative size is also stored on a sys_file row, which is wrong data at rest.
Mechanism confirmed on main: line 917 checks only size == null, and line 929 calls requireWithinUploadLimit(Number(size), …), which lets NaN and negative values through to the insert.
Responsibility: (1) the platform's presign door produces the risk. (2) The sys_file field validation already covers NaN, but it surfaces as a 500 instead of a 400, and nothing covers a negative size. (3) Any signed-in uploader reaches it.
Prior rulings read: check-prior-rulings.mjs --card 27413 named no decision that governs the size parameter. The hits were term noise (ADR-0005 §8, ADR-0007 §4, ADR-0019, ADR-0028 D2).
Type: Bug.
Fold suggestion (the execution seat decides): fold with #27412, for the same file and the same class of validation; see the note there. Draft PR #27424 does not touch storage-routes.ts, so it is disjoint.
Claim: PM loop round 1
Session: session_017xRBcScm27Q3R5mkYLPWdB
Account: sunhaolin
Branch: claude/issue-27412-storage-route-input
Worktree: objectstack-issue-27413
Domain: domain:server
Seat: domain:devx#1
File surface: as on #27412 (one branch for the fold): storage-routes.ts presign size check, its tests, the same changeset (stop on breach; explain in the report)
Container & model: M, mode:subagent, model: default (dispatch-gates --tier at c4c515a: "no path-derived mandate"), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: service-storage route code: requireWithinUploadLimit(Number(size)) lets NaN and negatives through | no platform path covers it | reached by any signed-in uploader
Thread-read: 6494074046
Premise: holds (triage first touch re-verified the mechanism on origin/main ded67bfb; the dev re-measures before editing)
Serial constraints cleared: see #27412 (chain head); none
Maintainer direct dispatch (cross-lane claim authority): the maintainer, in session session_017xRBcScm27Q3R5mkYLPWdB on 2026-10-29, verbatim: 「你应该使用 pm-dispatch 技能处理 issue 和 pr」. This devx-seat session claims these domain:server cards on that instruction; the card stays domain:server.
Fold member of the #27412 family dispatch: branch claude/issue-27412-storage-route-input, the full serial-constraint check and the five fold gates are on #27412.
ACCEPT → PR #27537 (head 41272f9f, contract review PASS 6496658225), reviewed 2026-10-29T12:29Z. Ready to land, held on the landing permission. Follow-up for the sibling init door and the spec size: #27549.
Activity
objectstack-fleet commentedon Oct 29, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 文件 | none | P②
Triage: p2 ·
domain:server·area:files· 2026-10-29T06:02Z⛔ Not a claim.
sizeand stores a negative one. A bad input should get a 400 with no row written. As it stands, the door stores wrong data and points operators at the server, so p2.400, with the field named.bug,pm:queue.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:devx#1 · sunhaolin · session_017xRBcScm27Q3R5mkYLPWdB
Path: 文件 | none | P②
Triage: lands in
packages/services/service-storage/src/storage-routes.ts(domain:server); rationale: this concurs with the first touch at 06:02Z (comment 6489280043). Labels stay as they are (bug,priority:p2,pm:queue,area:files,domain:server). This note adds the parts of the first touch that the duties require and that were missing. Read at origin/mainded67bfb, 2026-10-29T09:55Z.sizeis also stored on asys_filerow, which is wrong data at rest.size == null, and line 929 callsrequireWithinUploadLimit(Number(size), …), which lets NaN and negative values through to the insert.sys_filefield validation already covers NaN, but it surfaces as a 500 instead of a 400, and nothing covers a negative size. (3) Any signed-in uploader reaches it.check-prior-rulings.mjs --card 27413named no decision that governs the size parameter. The hits were term noise (ADR-0005 §8, ADR-0007 §4, ADR-0019, ADR-0028 D2).Fold suggestion (the execution seat decides): fold with #27412, for the same file and the same class of validation; see the note there. Draft PR #27424 does not touch
storage-routes.ts, so it is disjoint.Size/model suggestion: S.
Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:devx#1 · sunhaolin · session_017xRBcScm27Q3R5mkYLPWdB
Claim: PM loop round 1
Session:
session_017xRBcScm27Q3R5mkYLPWdBAccount:
sunhaolinBranch:
claude/issue-27412-storage-route-inputWorktree:
objectstack-issue-27413Domain:
domain:serverSeat:
domain:devx#1File surface: as on #27412 (one branch for the fold):
storage-routes.tspresignsizecheck, its tests, the same changeset (stop on breach; explain in the report)Container & model:
M,mode:subagent,model: default(dispatch-gates --tierat c4c515a: "no path-derived mandate"),effort: highClause-②: no
Metadata-protocol: none
Responsibility: service-storage route code:
requireWithinUploadLimit(Number(size))lets NaN and negatives through | no platform path covers it | reached by any signed-in uploaderThread-read: 6494074046
Premise: holds (triage first touch re-verified the mechanism on origin/main
ded67bfb; the dev re-measures before editing)Serial constraints cleared: see #27412 (chain head); none
Maintainer direct dispatch (cross-lane claim authority): the maintainer, in session
session_017xRBcScm27Q3R5mkYLPWdBon 2026-10-29, verbatim: 「你应该使用 pm-dispatch 技能处理 issue 和 pr」. This devx-seat session claims these domain:server cards on that instruction; the card staysdomain:server.Fold member of the #27412 family dispatch: branch
claude/issue-27412-storage-route-input, the full serial-constraint check and the five fold gates are on #27412.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:devx#1 · sunhaolin · session_017xRBcScm27Q3R5mkYLPWdB
ACCEPT → PR #27537 (head
41272f9f, contract review PASS 6496658225), reviewed 2026-10-29T12:29Z. Ready to land, held on the landing permission. Follow-up for the sibling init door and the specsize: #27549.Generated by Claude Code
objectstack-fleet commentedon Oct 29, 2026
domain:devx#1 · sunhaolin · session_017xRBcScm27Q3R5mkYLPWdB
Handover: PR #27537 → PM session session_017xRBcVy4VXmkQjn2MGeaWk (review and landing)
Generated by Claude Code