[Bug]: Guest messages near the 4,000-char limit fail with 400 "The request was not valid." because multipart turns \n into \r\n
I maintainer di solito rispondono entro 1 giorno
@juliusmarminge ci sta già lavorando.
Dal 28/10/2026.
Valutazione
- Difficoltà
- 2/5
- Tempo stimato
- 1-3 ore
- Idoneità per principianti
- 76/100
- Tipo di issue
- Bug
- Chiarezza
- Specificata chiaramente
- Stato di attività
- Attiva
- Stack tecnologico
- node.js, typescript
Direzione di ricerca
Leggi apps/server/src/guest/http.ts:192 e il percorso circostante readSubmission/decodeSubmit fino al generico badRequest alla riga 219. Riproduci inviando un messaggio guest multipart la cui lunghezza tipizzata è sotto 4.000 ma la cui lunghezza sul wire cresce da \n a \r\n, poi normalizza i fine riga prima di isMaxLength e restituisci un motivo too_long specifico. Fatto significa che un tale messaggio viene accettato, memorizzato con \n, e un messaggio realmente troppo grande riceve un errore distinto.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Before submitting
- I searched existing issues and did not find a duplicate.
- I included enough detail to reproduce or investigate the problem.
Area
Guest share links (T3 Connect "share with link")
Steps to reproduce
- Share a thread with a link, open it as a guest, enter a name.
- In the guest composer, type or paste a multi-line message that is under 4,000 characters, but where the length plus the number of line breaks is over 4,000 (for example a long email draft with paragraphs).
- Send it.
Expected behavior
The message is accepted. The textarea's maxLength={GUEST_MESSAGE_MAX_LENGTH} let it through, so the server should accept it too. If the message really is too long, the guest should see a specific error.
Actual behavior
POST /api/guest/messages returns 400 and the guest sees "The request was not valid." Retrying fails the same way (8 attempts in my logs).
Cause: GuestComposer sends the text through FormData. Multipart/form-data serialization turns every \n in string entries into \r\n (per the HTML spec; Chrome and undici both do this). The server then decodes parts.text with TrimmedString.check(isMaxLength(GUEST_MESSAGE_MAX_LENGTH)) (apps/server/src/guest/http.ts:192). That check counts each line break as 2 characters, so the decode fails and the route falls through to the generic badRequest (http.ts:219).
Repro of the inflation in Node 26:
const t = "a\n".repeat(2000).slice(0, 3999);
const fd = new FormData(); fd.append("text", t);
const body = await new Response(fd).text();
// client length 3999 -> wire length 5998
Two smaller issues on the same path:
- Accepted multi-line guest messages are stored with
\r\n. - A schema failure (for example the text being too long) comes back as
reason: "invalid"/ "The request was not valid." instead of a specific reason liketoo_long, so the guest can't tell what to fix.
Impact
Guests can't send longer, formatted messages, and the error gives them no hint about why. In practice the feature looks broken.
Version or commit
0.1.4-nightly.20261028.3824 (desktop, Windows + WSL server)
Environment
Owner: T3 Code Nightly desktop on Windows, server in WSL2. Guest: browser, through the *.t3coderelay.com relay.
Logs or stack traces
Server trace, all on share 1FLJ…:
16:11:29 POST /api/guest/redeem 204
16:20:08 POST /api/guest/messages 400
... (x8, last at 16:22:06)
GuestShareService.check succeeds on each of these requests, so the session is valid. The 400 comes from readSubmission/decodeSubmit.
Why it has to be the text length:
- The
shareIdwas the same in the failing requests and the successful ones. - Attachments work: one of the later, accepted messages had a PNG attached.
- "The request was not valid." comes only from
badRequest, so the multipart parse succeeded. The only check left that can fail isisMaxLengthontext.
At 15:25 the guest split the same content into two messages (770 and 3285 characters as typed), and both were accepted (204). Both are stored with \r\n line endings (2 and 19 of them), which confirms the normalization happens on the way to the server. The textarea's maxLength also cuts pasted text silently at 4000, so a long paste is the easiest way to hit this: 4000 characters plus N newlines.
Workaround
Shorten the message so that its length plus the number of line breaks is ≤ 4,000, or put the long text in an attached .txt file.
Suggested fix: on the server, normalize \r\n → \n before the length check (or send the text as JSON next to the files). Also return a specific too_long reason, and optionally show a character counter in the guest composer.
🤖 Opus 5.5 on behalf of the user
- Lingua principale
- TypeScript
- Stelle
- 24.8k
- Fork
- 6.4k
- Merge medio
- 3h 21m
- PR unite (30g)
- 297
Preparare l'ambiente
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di pingdotgg/t3code
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
"Open question" banner opens an empty new thread when the child thread runs on a linked environmentAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 74/100
I maintainer di solito rispondono entro 1 giorno
-
[Bug]: Settled list toggle is obscured by bottom navigation on unfolded iPhone Duo in portraitAperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 66/100
pingdotgg/t3code#26989 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di pingdotgg/t3code
Issue simili
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 76/100
Graphify-Labs/graphify#4860 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
sveltejs/eslint-plugin-svelte#1615 ·
I maintainer di solito rispondono entro 7 giorni
-
Parallel reticle_verify opens per-flow leases without the source lease's ignoreHTTPSErrorsForse già presa @as992949791 l’ha presa oggi. Apertagood first issue help wanted
Difficoltà 2/5 1-3 ore Idoneità per principianti 85/100
reticlehq/reticle#2033 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno
-
bug
Difficoltà 2/5 1-3 ore Idoneità per principianti 68/100
I maintainer di solito rispondono entro 1 giorno
-
area:quality p3-medium ready-for-agent type:docs
Difficoltà 2/5 1-3 ore Idoneità per principianti 83/100
fderuiter/deruiter.dev#3589 · 1 commento ·
I maintainer di solito rispondono entro 1 giorno