openai / openai/codex

Codex 0.153.4: hardcoded 60-second file-upload timeout cancels valid uploads

Open
#44,372 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI connectivity tool-calls
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

Summary

In Codex 0.153.4, the native file uploader cancels a valid blob PUT after a hardcoded 60 seconds even when the surrounding tool execution has a longer deadline. Three clean attempts to upload the same 39,439,093-byte Sites package failed after 60.005 s, 60.001 s, and 60.005 s.

A local patch routes a configurable upload deadline through the existing typed configuration and HTTP client, defaulting to 180 seconds. The patched Linux build passed 788 relevant tests, including a real streaming-upload regression lasting 65.126 seconds, and successfully saved the unchanged production package in approximately 71.5 seconds. That saved version was subsequently deployed and verified. The production measurement covers the entire save call; the controlled regression independently establishes that the PUT itself can exceed 60 seconds.

Environment and exact source

Item Value
Codex version codex-cli 0.153.4
Official tag rust-v0.153.4
Exact source commit 3d2ee51ca2d5db578f328aa75e20aa22c0197c9a
Original failure environment Windows 11 Home, build 26200, x86_64; native authenticated Sites file upload
Linux build and verification Microsoft WSL 2.7.13.0, WSL2; Ubuntu 24.04.4 LTS
Linux kernel 6.18.33.2-microsoft-standard-WSL2, x86_64
Toolchain Rust/Cargo 1.95.0, target x86_64-unknown-linux-gnu; Just 1.58.0; nextest 0.9.143
Local binary profile Existing dev-small profile, unoptimized and stripped
Authentication Normal ChatGPT sign-in; native Sites tools

The issue is in the file transport, not a model response. The reproduction and validation below are for this exact release; they do not claim a test of every platform or the latest development branch.

Reproduction and actual behavior

  1. Use stock Codex 0.153.4 with a normally authenticated Sites connection.
  2. Call the native Sites save_site_version workflow with an absolute path to a valid local archive whose transfer takes more than 60 seconds on the available connection. Use a test project when reproducing; saving a version does not require publishing it.
  3. Give the surrounding tool execution a deadline greater than 60 seconds.
  4. Observe the file blob PUT time out at approximately 60 seconds, before the version can be saved. Retry with the same bytes to distinguish the deadline from a packaging change.

Three consecutive clean attempts on September 9, 2026:

Attempt Archive bytes Blob PUT elapsed Result
1 39,439,093 60.005 s Transport timeout
2 39,439,093 60.001 s Transport timeout
3 39,439,093 60.005 s Transport timeout

Representative diagnostic, with the upload host and request identifier redacted:

OpenAI file blob upload to <upload-host> failed after 60005 ms (timeout, azure_client_request_id=<redacted>): error sending request

Sites did not return a package-size rejection. A 38,104,385-byte archive successfully used the same deployment path the previous day. That earlier whole save call took 65.345 seconds; its isolated PUT duration was not captured. Neither observation establishes a universal size threshold or a Sites size limit. No archive rebuild or modification occurred between the three failing attempts and the patched successful attempt.

Root cause

At the exact release commit, codex-rs/codex-api/src/files.rs defines:

const OPENAI_FILE_REQUEST_TIMEOUT: Duration = Duration::from_secs(60);

upload_openai_file applies it directly to the streaming blob PUT:

client_pool
    .put(&create_payload.upload_url)
    .timeout(OPENAI_FILE_REQUEST_TIMEOUT)

The same constant separately bounds authenticated metadata requests. RouteAwareRequestBuilder::timeout sets a whole-request deadline. The pool starts the budget before outbound-route resolution, includes connection establishment, request transmission and waiting for the response, and passes the remaining budget to reqwest. Increasing an outer MCP/tool/command deadline cannot extend that inner deadline.

The uploader permits files up to 512 MiB, but the fixed transmission budget can cancel a valid transfer well below that size. The exact 60-second failures, source-level deadline and controlled delayed-body test identify the client request timeout as the bottleneck.

Expected behavior and proposed approach

A valid upload should be allowed to finish within its configured file-upload budget, while still timing out if that budget is exceeded.

The local patch adds positive-integer file_upload_timeout_sec to the existing typed ConfigToml as Option<NonZeroU64>, resolves it to a runtime Duration with a 180-second default, and passes it through the existing MCP file-upload call to upload_openai_file. Only the PUT changes from .timeout(OPENAI_FILE_REQUEST_TIMEOUT) to .timeout(upload_timeout).

file_upload_timeout_sec = 180

An explicit CLI override also works, for example -c file_upload_timeout_sec=240. This setting is part of the local patch, not an existing stock 0.153.4 option.

Metadata and finalization deadlines, file-size validation, authentication, routing and existing retry behavior remain unchanged. The patch does not increase unrelated outer command timeouts. The original timeout/test patch changes six files, with 133 insertions and one deletion; it was applied unchanged for the Linux build.

Regression reproduction without a production package

The prepared tests use the existing wiremock server and actual route-aware HTTP uploader:

  1. Mock the file-creation POST to return a local upload URL.
  2. Supply a streaming body using futures::stream::once, sleeping for 65 real seconds before yielding the five bytes hello; no paused Tokio clock is used.
  3. Mock the PUT to require content length 5 and the exact body, then mock the uploaded/finalization POST to return successful metadata.
  4. Call upload_openai_file with a 180-second deadline. Assert success, expected file metadata, and elapsed time of at least 65 seconds.
  5. Separately use a 100-millisecond deadline and a five-second body delay. Assert OpenAiFileError::BlobUploadRequest with source.is_timeout().
  6. Verify positive configuration values deserialize; zero, negative, fractional and non-numeric values fail. Verify runtime omission resolves to 180 seconds and an explicit 240-second override is respected.

The deliberate 65-second test has a narrowly scoped nextest allowance: package(codex-api) & test(upload_openai_file_can_exceed_sixty_seconds), with slow-timeout = { period = "90s", terminate-after = 2 }. This only prevents the test runner's own 60-second limit from killing the regression; the production fix is the inner PUT deadline described above.

Build and test evidence

The initial Windows-native build was blocked when Cargo tried to execute its newly compiled serde_json build helper: Windows Application Control / OS error 4551. Code Integrity events 3077 and 3033 confirmed the signing-policy restriction. This was a separate build-host blocker, not the cause of the upload failure.

Microsoft's supported WSL installer was used with normal administrator/UAC approval. Compilation and all tests then ran entirely inside Linux. Windows security policy was not disabled, weakened or modified. The final CLI/helper build completed successfully in 6 minutes 10 seconds, exit code 0, and the ELF binary returned codex-cli 0.153.4.

Commands run from the patched codex-rs tree:

just fmt
git diff --check
just write-config-schema
just test --cargo-profile dev-small -p codex-api -p codex-config
just test --cargo-profile dev-small -p codex-core --lib -E 'test(config::tests::) | test(mcp_openai_file::)'

Sanitized nextest excerpts, with progress ordinals omitted:

PASS [  65.126s] codex-api files::tests::upload_openai_file_can_exceed_sixty_seconds
PASS [   0.223s] codex-api files::tests::upload_openai_file_enforces_configured_timeout
PASS [   0.022s] codex-config config_toml::tests::file_upload_timeout_requires_positive_seconds
Summary [  65.333s] 467 tests run: 467 passed, 0 skipped

PASS [   0.098s] codex-core config::tests::load_config_applies_file_upload_timeout
Summary [   2.990s] 321 tests run: 321 passed, 2115 skipped

788 selected tests passed, with zero failures. The 2,115 other core tests were excluded by the stated filter, not run. The API/config wrapper initially used an incorrect path when copying JUnit after the successful tests; the original report was recovered without rerunning them. Test counts and timings were checked against both nextest logs and JUnit.

Formatting, schema generation and diff checks passed. Beyond the unchanged six-file timeout patch, the compiled tree contains only the generated six-line configuration schema addition and release-lock normalization of 149 local workspace versions from 0.0.0 to 0.153.4. Every external dependency and other lockfile field remained unchanged. No Linux-specific timeout source adjustment or unrelated code change was required.

Local artifact SHA-256 values retained for provenance:

original timeout/test patch: f7a0aaabd1dfff3c181f74c91bb394a946536ae0c2419858dfa56c363fda7989
complete compiled diff:     a95607e9d728fe5530311c2bb36e83612b5b87158489653b6dbcaeb6d1471ade
patched Linux CLI:          c160c92a2d7f14f39b0c09a5a29d22e3d473032226e0598eb9527eb382e7c613

Successful real upload and deployment

The patched CLI authenticated inside WSL through ordinary codex login, then successfully saved the original 39,439,093-byte archive using native Sites save_site_version and file_upload_timeout_sec=180. No Windows credentials were manually transferred, and no account-security setting was changed.

Sanitized timing fields from the deployment record:

tool: sites.save_site_version
started_utc: 2026-09-10T01:22:33.218547Z
completed_utc: 2026-09-10T01:23:44.335681Z
wrapper_monotonic_elapsed_seconds: 71.520
utc_event_timestamp_span_seconds: 71.117134
result: version saved successfully
input_archive_bytes: 39439093
input_archive_sha256: 4042fa3ed2a9dff1886b82fb8f1eeb96d5d197fbb43d157064a76abe1693a861

These are whole-save-call measurements, including upload and save processing; isolated production PUT timing was not captured. The 65.126-second controlled regression is the direct evidence that the patched PUT survives beyond 60 seconds. The production archive's bytes and SHA-256 were verified unchanged before and after; it was not rebuilt or repackaged.

The saved version was published successfully at 2026-09-10 01:25:14 UTC through the existing desktop session's normal native Sites tool after the noninteractive CLI's publish request was rejected before dispatch by its approval policy. The same saved version was reused with no second upload and no approval-policy bypass. Production verification passed for 24 pages, 10 exact image hashes and 22 desktop/mobile cases, including metadata and image checks.

The stock Windows Codex installation, binary and configuration were preserved for immediate rollback. Windows security policy was not modified. No site content, images, metadata, DNS or production architecture was changed as part of the timeout workaround.

Prior issue search and contribution scope

I searched open and closed issues for the timeout constant, uploader function, file-upload timeout configuration, files.rs, Sites saves and 60-second upload failures. I found no clear matching report. #41985 concerns a missing pre-header deadline on streaming Responses POSTs; it cites file requests as an example of bounded requests. #24262 concerns retaining a desktop performance-trace artifact after a Sentry upload timeout. Neither describes this native file PUT deadline or reproduction.

This report provides reproduction details, sanitized diagnostics, root-cause analysis and a tested proposed approach under the repository's current contribution guidance. No pull request is being submitted. Private project URLs, signed upload URLs, request identifiers, account details and customer data are omitted.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in codex-rs/codex-api/src/files.rs at upload_openai_file, then read RouteAwareRequestBuilder::timeout and the typed ConfigToml configuration path. Run the named upload_openai_file_can_exceed_sixty_seconds and upload_openai_file_enforces_configured_timeout tests, plus the configuration validation tests. Done means uploads can exceed 60 seconds within the configured budget while shorter deadlines still time out and existing metadata behavior remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, backend, testing-qa
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
70/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.