Skip to content

fix(x): drop chunked upload chunk size from 5MB to 1MB#31

Merged
paulocastellano merged 1 commit into
mainfrom
fix/x-chunked-upload-413
May 12, 2026
Merged

fix(x): drop chunked upload chunk size from 5MB to 1MB#31
paulocastellano merged 1 commit into
mainfrom
fix/x-chunked-upload-413

Conversation

@paulocastellano
Copy link
Copy Markdown
Contributor

Context

Every video post to X has been failing in production with the cryptic error 'An unknown X error occurred.' Logs show the pattern:

```
production.ERROR: X chunked upload APPEND error {"status":413,"body":"","segment":0}
production.ERROR: Social publish failed: An unknown X error occurred.
```

Status 413 with empty body on the very first chunk — the classic signature of an edge/CDN rejection (the gateway is denying the request before X's application code sees it).

Root cause

We were using 5MB chunks (max documented size per X v2 reference), but every canonical reference uses 1MB:

  • X's official Python quickstart: `chunk_size = 1024 * 1024`
  • X's official JavaScript quickstart: `const chunkSize = 1024 * 1024`
  • twitter-api-v2 (the most-used Node SDK, used by Postiz and the broader ecosystem): `chunkSize: number = 1024 * 1024` as the default

The docs say 5MB max, but with multipart-form overhead, the actual HTTP request body exceeds an undocumented edge limit. 1MB is the empirically safe size everyone converges on.

Changes

  1. XPublisher.php:209 — drop chunk size from `5 * 1024 * 1024` to `1024 * 1024`. An 8MB video uploads as 8 APPEND segments instead of 2; more roundtrips but actually succeeds.

  2. XPublisher.php:224 — set explicit `Content-Type` on each chunk attach (matches the simple-upload path in the same file at line 144-151).

  3. `XPublishException::fromApiResponse` — map HTTP 413 to `ErrorCategory::MediaFormat` with the message 'Media chunk rejected by X (payload too large).' so we don't surface 413 as 'unknown' if it ever recurs for any reason.

Test plan

  • `php artisan test --compact --parallel` — 1503 passed, 2 skipped, 0 failed (+1 over main, the new 413 mapping test)
  • New unit test: `HTTP 413 with empty body maps to MediaFormat category`
  • Manual production verification: post an 8MB video to X via the production app after deploy → confirm successful publish (no more 'unknown' errors)

Production was returning HTTP 413 with empty body on the first APPEND
segment of every video upload to X v2 — surfacing to users as 'An
unknown X error occurred.'

Empty-body 413 is the classic signature of an edge/CDN rejection: the
X gateway is denying the request before X's application code sees it.
The X v2 reference docs say 'max chunk size: 5MB', but every canonical
reference uses 1MB:
- X's official Python quickstart: `chunk_size = 1024 * 1024`
- X's official JavaScript quickstart: `const chunkSize = 1024 * 1024`
- twitter-api-v2 (the most-used Node SDK, used by Postiz et al.):
  `chunkSize: number = 1024 * 1024`

5MB plus multipart-form overhead apparently exceeds an undocumented
edge limit. 1MB is the empirically safe size everyone converges on.

Changes:
- XPublisher chunked APPEND now uses 1MB chunks. An 8MB video uploads
  as 8 segments instead of 2; more roundtrips but actually succeeds.
- Set explicit Content-Type on each chunk attach (matches the simple
  upload path in the same file).
- XPublishException::fromApiResponse maps HTTP 413 to
  ErrorCategory::MediaFormat with the message 'Media chunk rejected
  by X (payload too large).' so we don't surface 413 as 'unknown' if
  it ever recurs.

Test: unit test covering the 413→MediaFormat mapping. Full suite green
(1503 passed, 2 skipped).
@paulocastellano paulocastellano merged commit 1bc1ec9 into main May 12, 2026
2 checks passed
@paulocastellano paulocastellano deleted the fix/x-chunked-upload-413 branch May 12, 2026 23:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant