Skip to content
This repository was archived by the owner on Oct 26, 2026. It is now read-only.
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

Closed as not planned

Description

@marchtian

What happens

In a create form with a required Field.file, picking a file with a Chinese name does nothing:

  • No upload request is sent (none shows in the network log).
  • No error toast appears.
  • The field stays empty.

Submitting then fails with 「扫描件不能为空」.

Picking the same bytes renamed to license.pdf works. The file appears under the drop zone, uploads, and the record saves with the attachment.

Repro

  • @objectstack/* 18.0.0, objectstack dev, locale zh-CN.
  • App: objectstack-ai/hotsrm main, object srm_supplier_certificate, field attachment: Field.file({ label: '扫描件', required: true }).
  • 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.

Activity

  1. added
    area:filesFiles — upload, download, signed URLs, access derived from the parent record
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Oct 23, 2026
  2. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    Contributor

    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)


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    Contributor

    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.

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    Contributor

    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

  5. objectstack-fleet commented on Oct 23, 2026

    @objectstack-fleet
    Contributor

    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 main 842a0aef with the showcase, and a console from objectui main 01b85d8. 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 main 01b85d8.
    • 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.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:filesFiles — upload, download, signed URLs, access derived from the parent recordbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p1

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions