Skip to content

fix: insert AI Gateway extproc after the buffer filter - #2227

Merged
nacx merged 4 commits into
envoyproxy:mainfrom
ChrisJBurns:ai-gateway-buffer-filter-insertion-ordering-bug-fi
Jun 12, 2026
Merged

fix: insert AI Gateway extproc after the buffer filter#2227
nacx merged 4 commits into
envoyproxy:mainfrom
ChrisJBurns:ai-gateway-buffer-filter-insertion-ordering-bug-fi

Conversation

@ChrisJBurns

@ChrisJBurns ChrisJBurns commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Description

Problem

If a buffer filter (envoy.filters.http.buffer) is added to the chain, for example via an EnvoyPatchPolicy to raise the request buffer limit, the AI Gateway extproc could be placed ahead of it. The AI Gateway extproc runs with RequestBodyMode: BUFFERED, so when it runs before the buffer filter it buffers the body against Envoy Gateway's default 32 KiB downstream per-connection limit and returns 413 Payload Too Large for larger bodies before the buffer filter's higher limit applies.

The buffer filter raises the stream's buffer limit to max_request_bytes, but only for filters that decode after it. This was hit in practice with large request bodies such as Gemini CLI tool definitions.

Solution

When a buffer filter sits at or after the computed ext_proc insertion point, insert the AI Gateway extproc immediately after the last buffer filter. Envoy Gateway already orders the buffer filter before ext_proc, so this honors that order. Behavior is unchanged when no buffer filter is present.

This works because EnvoyPatchPolicy patches are applied before the extension hook runs and Envoy Gateway does not re-sort filters afterward, so the buffer filter is visible to this code.

The extension server only moves its own filter, not the user's buffer filter, so this fixes the 413 for AI Gateway's extproc specifically and not for other co-resident BUFFERED ext_procs.

Testing

Added table tests for three cases: ext_proc before buffer (inserted after buffer), buffer before ext_proc (inserted after buffer), and no buffer filter (unchanged).

When an EnvoyPatchPolicy (or similar) adds an HTTP buffer filter to raise
the request buffer limit, insertAIGatewayExtProcFilter could place the AI
Gateway extproc ahead of the buffer filter. Because that extproc runs in
RequestBodyMode: BUFFERED, it then buffers the request body against Envoy
Gateway's default 32 KiB downstream per-connection buffer limit and
rejects large request bodies with 413 Payload Too Large before the buffer
filter's larger limit can take effect. (This is the downstream listener
limit, not the 50 MiB limit AI Gateway sets on its extproc UDS cluster.)

Envoy Gateway's canonical filter order already places the buffer filter
before the ext_proc filters, so when a buffer filter sits at or after the
chosen insertion point, insert the AI Gateway extproc immediately after
the last buffer filter. The AI Gateway extproc is then the first ext_proc
filter to run after the buffer filter rather than the first ext_proc
filter overall, so a user-supplied ext_proc placed ahead of the buffer
filter still runs before it. Behavior is unchanged when no buffer filter
exists.

The extension server only changes the placement of its own filter; it
does not relocate the user's buffer filter, so this fixes the 413 for AI
Gateway's BUFFERED extproc specifically rather than for every co-resident
ext_proc.

Signed-off-by: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com>
@ChrisJBurns
ChrisJBurns requested a review from a team as a code owner June 12, 2026 01:00
@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Jun 12, 2026
@codecov-commenter

codecov-commenter commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 84.75%. Comparing base (3f817c0) to head (36dd3f6).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2227      +/-   ##
==========================================
+ Coverage   84.73%   84.75%   +0.01%     
==========================================
  Files         144      144              
  Lines       21189    21195       +6     
==========================================
+ Hits        17955    17963       +8     
+ Misses       2152     2151       -1     
+ Partials     1082     1081       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@johnugeorge

Copy link
Copy Markdown
Contributor

@siddharth1036

@nacx

nacx commented Jun 12, 2026

Copy link
Copy Markdown
Member

/reetst

@siddharth1036

Copy link
Copy Markdown
Contributor

Hi @ChrisJBurns , just wanted to check I am working on a PR: #2158 where you will be able to configure exact (or prefixed, under discussion) filter name which would be allowed to run before ai-gateway-extproc, could it be useful to solve your usecase as well?

@nacx
nacx merged commit 61b4cc8 into envoyproxy:main Jun 12, 2026
34 checks passed
@ChrisJBurns

Copy link
Copy Markdown
Contributor Author

Thanks for flagging this @siddharth1036 - we're definitely in the same code path. I think they're complementary rather than overlapping though: your allowlist is opt-in, but the buffer filter ordering needs to apply by default since it's a correctness fix (large bodies get a 413 otherwise). Could we treat the buffer filter as an always-on default in #2158, or let the automatic buffer handling stack on top of your allowlist?

hustxiayang pushed a commit to hustxiayang/ai-gateway that referenced this pull request Jun 12, 2026
**Description**

**Problem**

If a buffer filter (`envoy.filters.http.buffer`) is added to the chain,
for example via an EnvoyPatchPolicy to raise the request buffer limit,
the AI Gateway extproc could be placed ahead of it. The AI Gateway
extproc runs with `RequestBodyMode: BUFFERED`, so when it runs before
the buffer filter it buffers the body against Envoy Gateway's default 32
KiB downstream per-connection limit and returns `413 Payload Too Large`
for larger bodies before the buffer filter's higher limit applies.

The buffer filter raises the stream's buffer limit to
`max_request_bytes`, but only for filters that decode after it. This was
hit in practice with large request bodies such as Gemini CLI tool
definitions.

**Solution**

When a buffer filter sits at or after the computed ext_proc insertion
point, insert the AI Gateway extproc immediately after the last buffer
filter. Envoy Gateway already orders the buffer filter before ext_proc,
so this honors that order. Behavior is unchanged when no buffer filter
is present.

This works because EnvoyPatchPolicy patches are applied before the
extension hook runs and Envoy Gateway does not re-sort filters
afterward, so the buffer filter is visible to this code.

The extension server only moves its own filter, not the user's buffer
filter, so this fixes the 413 for AI Gateway's extproc specifically and
not for other co-resident BUFFERED ext_procs.

**Testing**

Added table tests for three cases: ext_proc before buffer (inserted
after buffer), buffer before ext_proc (inserted after buffer), and no
buffer filter (unchanged).

Signed-off-by: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com>
Co-authored-by: Ignasi Barrera <ignasi@tetrate.io>
Signed-off-by: yxia216 <yxia216@bloomberg.net>
hustxiayang pushed a commit to hustxiayang/ai-gateway that referenced this pull request Jun 16, 2026
**Description**

**Problem**

If a buffer filter (`envoy.filters.http.buffer`) is added to the chain,
for example via an EnvoyPatchPolicy to raise the request buffer limit,
the AI Gateway extproc could be placed ahead of it. The AI Gateway
extproc runs with `RequestBodyMode: BUFFERED`, so when it runs before
the buffer filter it buffers the body against Envoy Gateway's default 32
KiB downstream per-connection limit and returns `413 Payload Too Large`
for larger bodies before the buffer filter's higher limit applies.

The buffer filter raises the stream's buffer limit to
`max_request_bytes`, but only for filters that decode after it. This was
hit in practice with large request bodies such as Gemini CLI tool
definitions.

**Solution**

When a buffer filter sits at or after the computed ext_proc insertion
point, insert the AI Gateway extproc immediately after the last buffer
filter. Envoy Gateway already orders the buffer filter before ext_proc,
so this honors that order. Behavior is unchanged when no buffer filter
is present.

This works because EnvoyPatchPolicy patches are applied before the
extension hook runs and Envoy Gateway does not re-sort filters
afterward, so the buffer filter is visible to this code.

The extension server only moves its own filter, not the user's buffer
filter, so this fixes the 413 for AI Gateway's extproc specifically and
not for other co-resident BUFFERED ext_procs.

**Testing**

Added table tests for three cases: ext_proc before buffer (inserted
after buffer), buffer before ext_proc (inserted after buffer), and no
buffer filter (unchanged).

Signed-off-by: Chris Burns <29541485+ChrisJBurns@users.noreply.github.com>
Co-authored-by: Ignasi Barrera <ignasi@tetrate.io>
Signed-off-by: yxia216 <yxia216@bloomberg.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M This PR changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants