Skip to content

Egress gateway returns 431 once the egress grant outgrows Bun's 16 KiB header limit #261

Description

@sisve

Summary

The egress grant sealed in service/src/egress-grant.ts lists every input file (id, storage_session_id, name) plus read_sessions, and is sent to the egress gateway in the X-CodeAPI-Egress-Grant header. Its size grows with the number of input files and the length of their names. The gateway is started with bun run src/egress-gateway.ts (service/Dockerfile.egress-gateway), so Bun's default 16 KiB header limit applies.

When the sealed grant exceeds that limit, the gateway answers 431 Request Header Fields Too Large to every egress call from the sandbox runner. The first of these is the .dirkeep marker fetch in Job.prime(), so the execution fails with a generic sandbox_execution_failed 500.

The default SANDBOX_MAX_INPUT_FILES is 256 (api/src/config.ts), and a grant listing 256 files is well over 16 KiB. We saw failures start somewhere between 70 and 120 input files, depending on file name length.

Environment

  • code-interpreter built from 737f498 plus an unrelated Redis retry patch. main (cf0e668) has the same code.
  • Kubernetes, hardenedSandboxMode: true, egressGrant.ledgerRequired: true, libkrun microVM (executionProfile: default)
  • Client: LibreChat with @librechat/agents 3.7.17, which sends every file in the conversation as an input file on each agent turn

Steps to reproduce

  1. Put about 120 files in one session, or send an execution request with more than about 100 entries in files with typical file names.
  2. Run any bash or python execution that uses them.

Expected

The execution runs. If there is a real limit, the request fails with a 4xx that names it, for example "too many input files".

Actual

sandbox-runner:

{"level":40,"msg":"Failed to auto-load .dirkeep markers","err":{"message":"HTTP error loading .dirkeep markers: 431","stack":"Error: HTTP error loading .dirkeep markers: 431\n    at fetchSessionMarkers (/sandbox_api/.build/index.js:319:6135)"}}
{"level":50,"msg":"Error executing job","err":{"message":"HTTP error loading .dirkeep markers: 431"}}

service-worker / api:

{"level":"error","message":"Error processing job Request failed with status code 500","responseError":"sandbox_execution_failed","status":500,"url":"http://codeapi-sandbox-runner:2000/api/v2/execute"}
{"level":"error","message":"... Error during execution: Error from sandbox: [sandbox_execution_failed] Sandbox execution failed"}

The client only gets a 500, which @librechat/agents shows as "Code execution is temporarily unavailable. Please retry."

Workaround

Start the gateway with a larger limit:

command: ["bun", "--max-http-header-size=131072", "run", "src/egress-gateway.ts"]

Checked in the pod: a 40 KB header to /live returns 200 with the flag and 431 without it.

Possible fixes

Any one of these would solve it:

  • Make the header limit configurable in the chart and Dockerfile (for example EGRESS_GATEWAY_MAX_HEADER_BYTES), with a default that fits SANDBOX_MAX_INPUT_FILES.
  • Keep the file list out of the header: send the grant in the request body, or store the full claims server-side (the egress ledger already exists) and seal only a reference.
  • At least, map a 431 from the gateway to an error that says what went wrong, not a generic sandbox_execution_failed.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions