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 }}
This repository was archived by the owner on Oct 26, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Oct 26, 2026. It is now read-only.
Console file field silently drops a picked file whose name is non-ASCII (e.g. 示例营业执照.pdf) #13413
Open 资质证书, click 新建, then click the 扫描件 drop zone and choose 示例营业执照.pdf.
Nothing is attached. Repeat with the file renamed to license.pdf and it attaches.
Observed in headless Chromium (Playwright 1.56). It reproduced both through the file chooser and through setInputFiles on the hidden input. I haven't checked desktop browsers by hand.
Expected
Non-ASCII filenames upload normally and keep their original display name. Chinese filenames are the norm for this app's users, such as scanned licenses and certificates. If an upload is rejected for any reason, the user sees an error instead of a silent no-op.
Triage: lands in the file field's pick → upload path in packages/fields (FileField.tsx and its upload helpers); the exact line is not located yet; rationale: transferred from objectstack (rule 1). A file whose name is non-ASCII sends no upload request and shows no error; the same bytes renamed to ASCII attach. Reproduce on current main first (measured on 18.0.0 in headless Chromium only), then find where the pick is dropped.
Path: files · 传得上、下得来 | attachments-storage.presigned-upload-roundtrip (P1 bound) | step ②
Grade: priority:p1 (kept as set at transfer) — P1 item attachments-storage.presigned-upload-roundtrip; a CJK filename is the norm for this product's users and the failure is silent. Renaming the file is a workaround, so drop to p2 if desktop browsers do not reproduce it.
Type: Bug
Session: session_01AkmasAfXt3cu83xGzkuKhe (objectstack triage, run on the maintainer's request in the project thread)
Claim: card thread · domain:ui seat 1 (seat post #5560, project run by the Sales account) · 2026-10-23T18:19Z
Session: session_01CRAXpHf2H9bHuo9gaKMVpg (a card thread of the project that runs domain:ui seat 1, dispatched by its coordinator; 由Sales账户的项目负责)
Account: os-sales (the seat's linked user; the card's assignee from this stroke)
Branch: claude/issue-13413-non-ascii-upload
Worktree: objectui-issue-13413
Domain: domain:ui
Seat: domain:ui#1
File surface: packages/fields/src/widgets/ (FileField.tsx and its upload helpers), packages/providers/src/UploadProvider.tsx (the console's presigned upload adapter), the tests of each, .changeset/ (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default judgment tier (dispatch-gates --tier --repo objectstack-ai/objectui names no path-derived mandate for this surface), effort: xhigh
Clause-②: no
Metadata-protocol: none
Responsibility: the code that drops the pick is not located yet; the reproduction on current main decides it, and the report names the line | none: no platform path uploads a non-ASCII-named pick today, per the card | every console user who picks a file with a non-ASCII name in a Field.file form; hotsrm's users do it daily
Thread-read: 6371608475
Serial constraints cleared: open objectui PRs read at claim time are #13395 (ActionRunner row guard), #13362, #13360, #13358 (CI), #13289 (release), #13028 (timings), #11845 and #11844 (dependencies); none touches these paths. Open claims in this lane: #13384 (ActionRunner), #13350, objectstack-ai/objectstack#25936, #13348 (CI); none names these files.
Plan, stated so the review can hold it to it:
Reproduce on current objectui main against a current objectstack server: a Field.file create form, a pick named 示例营业执照.pdf against the same bytes named license.pdf, in headless Chromium, reading the network log and the field.
Find where the non-ASCII pick is dropped. If the root cause is in the objectstack server (service-storage routes or the HTTP layer), it is reported to the server lane and not fixed from this card.
Fix it in the upload path so the pick uploads and keeps its original display name, and make any refused upload show an error instead of a silent no-op.
os-dev-report
{
"issue": 13413,
"status": "done",
"branch": null,
"pr": null,
"session": "session_01CRAXpHf2H9bHuo9gaKMVpg",
"premise_still_valid": false,
"summary": "Reproduced, and the drop is not in the console. A non-ASCII-named file picked from disk is discarded by Chromium itself when the browser process runs without a UTF-8 locale (LANG and LC_ALL unset, so POSIX, which is the default in a bare container). The page then receives a change event whose file list is EMPTY: FileField has no file to upload and nothing that names the dropped one, so no request goes out and no error can be shown. The same browser binary launched with LANG=C.UTF-8 and LC_ALL=C.UTF-8 uploads the same file through all three steps (presigned, PUT, complete) by file chooser, by setInputFiles with a path and by setInputFiles with a buffer, and the field shows 示例营业执照.pdf. Under POSIX, the buffer form (a file built in the page, no disk path) also uploads, which is why the drop follows the path and not the bytes. The console code on this path (FileField.tsx, UploadProvider.tsx, createAuthenticatedFetch.ts, apps/console App.tsx) is blob-identical between objectui 616df65, the console that objectstack 18.0.0 ships, and main 01b85d8, so the reading on main covers the reporter's 18.0.0. The server stores and serves the name correctly: sys_file.name reads 示例营业执照.pdf, and the download answers content-disposition with an ASCII fallback plus filename* UTF-8 percent-encoded. Recommendation for the seat: close not_planned as an environment artefact of the headless harness, with the remedy for the reporter: launch Chromium with LANG=C.UTF-8 (for example chromium.launch with env LANG and LC_ALL set, or ENV LANG=C.UTF-8 in the container image), or use the buffer form of setInputFiles. Desktop browsers were not measured here; the triage grading clause (drop to p2 if desktop browsers do not reproduce) is the seat's alternative if it prefers to keep the card open until a desktop reading exists.",
"tests": "Live rig: objectstack main 842a0aef (pnpm build, 76/76 tasks), examples/app-showcase booted with objectstack dev --seed-admin --fresh -p 4010; console from objectui main 01b85d8 (pnpm run setup at its pin, then vite dev on :5190 proxying /api to :4010); field showcase_field_zoo.f_file (Field.file) in the create dialog, context locale zh-CN, browser chromium_headless_shell-1243 driven by @playwright/test 1.62.1. Matrix for 示例营业执照.pdf against license.pdf (same bytes), recording every /storage/ request: browser locale POSIX, pick by path: license.pdf presigned 200 + complete 200 and the field lists it; 示例营业执照.pdf no request, no console error, field empty. POSIX, pick by file chooser: same split (this is the card's chooser reading). POSIX, setInputFiles with a buffer: both upload and both names show. Browser LANG=LC_ALL=C.UTF-8, all three pick modes: both upload and both names show. Bare file input on a blank page, setInputFiles(path), reading the change event's files: POSIX gives license.pdf (14 bytes, readable) and an EMPTY list for 示例营业执照.pdf; C.UTF-8 gives both, readable. The full chromium-1243 build (not the headless shell) gives the same POSIX drop and C.UTF-8 upload on the console's first file input. Download side, by curl: presigned 200, PUT 200, complete 200, GET files/ID 302 then 200 with content-disposition inline, filename ASCII fallback and filename* UTF-8 percent-encoded 示例营业执照.pdf; sys_file.name reads back 示例营业执照.pdf. Control that a FAILED upload is reported: pnpm exec vitest run packages/fields/src/widgets/fileSubmitRequiresId-7699.test.tsx, 11 passed (the inline Failed to upload / did not complete rows under the drop zone; the widget reports per pick inline, not as a toast). Probe scripts and the full matrix log are in the project's shared folder issue-13413 (repro.cjs, probe-input.cjs, probe.log).",
"gates": "n/a: no code change, no branch pushed, no PR",
"dogfood_battery": "n/a: no PR",
"mcp_calls": "2, both read-only: issue_read 2 (this card, its comments). No MCP write tool.",
"api_writes": "3, through the scripts/pm fleet-write relay as objectstack-fleet[bot]: label-write on this card (pm:queue removed, pm:dispatched added, assignee os-sales); claim comment 6371772573; this report comment. No git push.",
"open_questions": [],
"out_of_scope_findings": []
}
Closing as not planned: the console does not drop the file; the headless browser does · domain:ui seat 1 (seat post #5560, project run by the Sales account) · session_01WJozybDmRH8z2c5SD7vJkj · 2026-10-23T18:46Z
The card thread re-measured this on a live rig. Its report is comment 6372080565 (premise_still_valid: false), under claim 6371772573.
Rig: objectstack main842a0aef with the showcase, and a console from objectui main01b85d8. The field was showcase_field_zoo.f_file in the create dialog, locale zh-CN. The browser was Playwright's Chromium (the headless shell and the full build).
Measured:
The drop happens before the page sees the file. The browser process ran without a UTF-8 locale (LANG and LC_ALL unset, so POSIX, the default in a bare container). Picking 示例营业执照.pdf from disk then hands the page a change event whose file list is empty. A bare <input type=file> on a blank page does the same. FileField has nothing to upload and nothing to report, which explains the "no request, no toast" reading.
Positive controls.
The same browser binary launched with LANG=C.UTF-8 / LC_ALL=C.UTF-8 uploads the same file. It completes all three steps (presigned, PUT, complete) by file chooser, by setInputFiles(path) and by setInputFiles(buffer), and the field shows the original name.
Under POSIX, the buffer form also uploads. So the drop follows the disk path, not the bytes.
Server side is correct.sys_file.name reads back 示例营业执照.pdf. The download answers content-disposition with an ASCII fallback plus filename* UTF-8.
The reporter's version is covered. The console files on this path are blob-identical between objectui 616df65 (the console objectstack 18.0.0 ships) and main01b85d8.
A failed upload is reported. The widget's per-pick inline failure rows are pinned (fileSubmitRequiresId-7699, 11 passed).
Remedy for the harness: launch Chromium with a UTF-8 locale, e.g. env: { LANG: 'C.UTF-8', LC_ALL: 'C.UTF-8' } on chromium.launch, or ENV LANG=C.UTF-8 in the container image. Alternatively, use the buffer form of setInputFiles.
Not measured: desktop browsers run with a user locale, so they are outside this reading. If a desktop browser reproduces the drop, reopen with that reading.
Activity
objectstack-fleet commentedon Oct 23, 2026
Triage: lands in the file field's pick → upload path in
packages/fields(FileField.tsxand its upload helpers); the exact line is not located yet; rationale: transferred from objectstack (rule 1). A file whose name is non-ASCII sends no upload request and shows no error; the same bytes renamed to ASCII attach. Reproduce on current main first (measured on 18.0.0 in headless Chromium only), then find where the pick is dropped.Path: files · 传得上、下得来 | attachments-storage.presigned-upload-roundtrip (P1 bound) | step ②
Grade:
priority:p1(kept as set at transfer) — P1 itemattachments-storage.presigned-upload-roundtrip; a CJK filename is the norm for this product's users and the failure is silent. Renaming the file is a workaround, so drop to p2 if desktop browsers do not reproduce it.Type: Bug
Session:
session_01AkmasAfXt3cu83xGzkuKhe(objectstack triage, run on the maintainer's request in the project thread)Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Claim: card thread ·
domain:uiseat 1 (seat post #5560, project run by the Sales account) · 2026-10-23T18:19ZSession:
session_01CRAXpHf2H9bHuo9gaKMVpg(a card thread of the project that runsdomain:uiseat 1, dispatched by its coordinator; 由Sales账户的项目负责)Account:
os-sales(the seat's linked user; the card's assignee from this stroke)Branch:
claude/issue-13413-non-ascii-uploadWorktree:
objectui-issue-13413Domain:
domain:uiSeat:
domain:ui#1File surface:
packages/fields/src/widgets/(FileField.tsxand its upload helpers),packages/providers/src/UploadProvider.tsx(the console's presigned upload adapter), the tests of each,.changeset/(stop on breach; explain in the report)Container & model:
M,mode:thread,model: default judgment tier (dispatch-gates --tier --repo objectstack-ai/objectui names no path-derived mandate for this surface),effort: xhighClause-②: no
Metadata-protocol: none
Responsibility: the code that drops the pick is not located yet; the reproduction on current main decides it, and the report names the line | none: no platform path uploads a non-ASCII-named pick today, per the card | every console user who picks a file with a non-ASCII name in a
Field.fileform; hotsrm's users do it dailyThread-read: 6371608475
Serial constraints cleared: open objectui PRs read at claim time are #13395 (ActionRunner row guard), #13362, #13360, #13358 (CI), #13289 (release), #13028 (timings), #11845 and #11844 (dependencies); none touches these paths. Open claims in this lane: #13384 (ActionRunner), #13350, objectstack-ai/objectstack#25936, #13348 (CI); none names these files.
Plan, stated so the review can hold it to it:
Field.filecreate form, a pick named示例营业执照.pdfagainst the same bytes namedlicense.pdf, in headless Chromium, reading the network log and the field.service-storageroutes or the HTTP layer), it is reported to the server lane and not fixed from this card.Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
os-dev-report
{
"issue": 13413,
"status": "done",
"branch": null,
"pr": null,
"session": "session_01CRAXpHf2H9bHuo9gaKMVpg",
"premise_still_valid": false,
"summary": "Reproduced, and the drop is not in the console. A non-ASCII-named file picked from disk is discarded by Chromium itself when the browser process runs without a UTF-8 locale (LANG and LC_ALL unset, so POSIX, which is the default in a bare container). The page then receives a change event whose file list is EMPTY: FileField has no file to upload and nothing that names the dropped one, so no request goes out and no error can be shown. The same browser binary launched with LANG=C.UTF-8 and LC_ALL=C.UTF-8 uploads the same file through all three steps (presigned, PUT, complete) by file chooser, by setInputFiles with a path and by setInputFiles with a buffer, and the field shows 示例营业执照.pdf. Under POSIX, the buffer form (a file built in the page, no disk path) also uploads, which is why the drop follows the path and not the bytes. The console code on this path (FileField.tsx, UploadProvider.tsx, createAuthenticatedFetch.ts, apps/console App.tsx) is blob-identical between objectui 616df65, the console that objectstack 18.0.0 ships, and main 01b85d8, so the reading on main covers the reporter's 18.0.0. The server stores and serves the name correctly: sys_file.name reads 示例营业执照.pdf, and the download answers content-disposition with an ASCII fallback plus filename* UTF-8 percent-encoded. Recommendation for the seat: close not_planned as an environment artefact of the headless harness, with the remedy for the reporter: launch Chromium with LANG=C.UTF-8 (for example chromium.launch with env LANG and LC_ALL set, or ENV LANG=C.UTF-8 in the container image), or use the buffer form of setInputFiles. Desktop browsers were not measured here; the triage grading clause (drop to p2 if desktop browsers do not reproduce) is the seat's alternative if it prefers to keep the card open until a desktop reading exists.",
"tests": "Live rig: objectstack main 842a0aef (pnpm build, 76/76 tasks), examples/app-showcase booted with objectstack dev --seed-admin --fresh -p 4010; console from objectui main 01b85d8 (pnpm run setup at its pin, then vite dev on :5190 proxying /api to :4010); field showcase_field_zoo.f_file (Field.file) in the create dialog, context locale zh-CN, browser chromium_headless_shell-1243 driven by @playwright/test 1.62.1. Matrix for 示例营业执照.pdf against license.pdf (same bytes), recording every /storage/ request: browser locale POSIX, pick by path: license.pdf presigned 200 + complete 200 and the field lists it; 示例营业执照.pdf no request, no console error, field empty. POSIX, pick by file chooser: same split (this is the card's chooser reading). POSIX, setInputFiles with a buffer: both upload and both names show. Browser LANG=LC_ALL=C.UTF-8, all three pick modes: both upload and both names show. Bare file input on a blank page, setInputFiles(path), reading the change event's files: POSIX gives license.pdf (14 bytes, readable) and an EMPTY list for 示例营业执照.pdf; C.UTF-8 gives both, readable. The full chromium-1243 build (not the headless shell) gives the same POSIX drop and C.UTF-8 upload on the console's first file input. Download side, by curl: presigned 200, PUT 200, complete 200, GET files/ID 302 then 200 with content-disposition inline, filename ASCII fallback and filename* UTF-8 percent-encoded 示例营业执照.pdf; sys_file.name reads back 示例营业执照.pdf. Control that a FAILED upload is reported: pnpm exec vitest run packages/fields/src/widgets/fileSubmitRequiresId-7699.test.tsx, 11 passed (the inline Failed to upload / did not complete rows under the drop zone; the widget reports per pick inline, not as a toast). Probe scripts and the full matrix log are in the project's shared folder issue-13413 (repro.cjs, probe-input.cjs, probe.log).",
"gates": "n/a: no code change, no branch pushed, no PR",
"dogfood_battery": "n/a: no PR",
"mcp_calls": "2, both read-only: issue_read 2 (this card, its comments). No MCP write tool.",
"api_writes": "3, through the scripts/pm fleet-write relay as objectstack-fleet[bot]: label-write on this card (pm:queue removed, pm:dispatched added, assignee os-sales); claim comment 6371772573; this report comment. No git push.",
"open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Oct 23, 2026
Closing as not planned: the console does not drop the file; the headless browser does ·
domain:uiseat 1 (seat post #5560, project run by the Sales account) ·session_01WJozybDmRH8z2c5SD7vJkj· 2026-10-23T18:46ZThe card thread re-measured this on a live rig. Its report is comment 6372080565 (
premise_still_valid: false), under claim 6371772573.Rig: objectstack
main842a0aefwith the showcase, and a console from objectuimain01b85d8. The field wasshowcase_field_zoo.f_filein the create dialog, locale zh-CN. The browser was Playwright's Chromium (the headless shell and the full build).Measured:
LANGandLC_ALLunset, so POSIX, the default in a bare container). Picking示例营业执照.pdffrom disk then hands the page achangeevent whose file list is empty. A bare<input type=file>on a blank page does the same.FileFieldhas nothing to upload and nothing to report, which explains the "no request, no toast" reading.LANG=C.UTF-8/LC_ALL=C.UTF-8uploads the same file. It completes all three steps (presigned, PUT, complete) by file chooser, bysetInputFiles(path)and bysetInputFiles(buffer), and the field shows the original name.sys_file.namereads back示例营业执照.pdf. The download answerscontent-dispositionwith an ASCII fallback plusfilename*UTF-8.616df65(the console objectstack 18.0.0 ships) andmain01b85d8.fileSubmitRequiresId-7699, 11 passed).Remedy for the harness: launch Chromium with a UTF-8 locale, e.g.
env: { LANG: 'C.UTF-8', LC_ALL: 'C.UTF-8' }onchromium.launch, orENV LANG=C.UTF-8in the container image. Alternatively, use the buffer form ofsetInputFiles.Not measured: desktop browsers run with a user locale, so they are outside this reading. If a desktop browser reproduces the drop, reopen with that reading.
Generated by Claude Code