Skip to content

exception fixes#2676

Merged
akshaydeo merged 1 commit intov1.5.0from
04-13-exception_fixes
Apr 13, 2026
Merged

exception fixes#2676
akshaydeo merged 1 commit intov1.5.0from
04-13-exception_fixes

Conversation

@akshaydeo
Copy link
Copy Markdown
Contributor

@akshaydeo akshaydeo commented Apr 13, 2026

Summary

Fixes context propagation for async job execution by ensuring that original request context values (virtual keys, tracing headers, etc.) are properly restored in background goroutines. This resolves issues where async operations would lose important request metadata needed for proper authentication, tracing, and plugin execution.

Changes

  • Modified AsyncJobExecutor.SubmitJob() to accept a contextValues parameter containing the original request's BifrostContext user values
  • Updated executeJob() to restore these context values on the background execution context before running the operation
  • Added comprehensive test coverage for context propagation scenarios including success, failure, and edge cases
  • Fixed streaming response handling to avoid accessing recycled fasthttp RequestCtx objects in goroutines by:
    • Creating snapshot functions that capture request/response data while the context is still valid
    • Implementing runTransportPostHooksCaptured() for goroutine-safe plugin execution
    • Updating trace completion callbacks to accept logs as parameters instead of reading from context
  • Added BuildHTTPResponseFromFastHTTP() utility function for creating response snapshots
  • Updated all async handler endpoints to pass context values when submitting jobs

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

How to test

Validate that async operations properly inherit request context:

# Run the new async job tests
go test ./framework/logstore -v -run TestSubmitJob

# Test full async workflow with context propagation
go test ./transports/bifrost-http/handlers -v -run TestAsync

# Verify no race conditions in streaming responses
go test -race ./transports/bifrost-http/handlers

# Run full test suite
go test ./...

Test async endpoints with virtual keys and custom headers to ensure context values are preserved in background execution.

Screenshots/Recordings

N/A

Breaking changes

  • Yes
  • No

Related issues

Addresses context loss in async job execution that could cause authentication failures and incomplete tracing data.

Security considerations

Improves security by ensuring virtual key validation and authentication context is properly maintained in async operations. No new security risks introduced as this only preserves existing context data.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: af4cf721-e4d0-468b-abc2-4488ccc87387

📥 Commits

Reviewing files that changed from the base of the PR and between 9a7503d and b208b52.

📒 Files selected for processing (42)
  • .github/workflows/scripts/run-migration-tests.sh
  • .gitignore
  • core/changelog.md
  • core/schemas/bifrost.go
  • core/version
  • framework/changelog.md
  • framework/configstore/migrations_test.go
  • framework/configstore/rdb_test.go
  • framework/logstore/asyncjob.go
  • framework/logstore/asyncjob_test.go
  • framework/vectorstore/redis_test.go
  • framework/version
  • plugins/compat/changelog.md
  • plugins/compat/version
  • plugins/governance/changelog.md
  • plugins/governance/version
  • plugins/jsonparser/changelog.md
  • plugins/jsonparser/version
  • plugins/litellmcompat/changelog.md
  • plugins/litellmcompat/version
  • plugins/logging/changelog.md
  • plugins/logging/version
  • plugins/maxim/changelog.md
  • plugins/maxim/version
  • plugins/mocker/changelog.md
  • plugins/mocker/version
  • plugins/otel/changelog.md
  • plugins/otel/version
  • plugins/prompts/changelog.md
  • plugins/prompts/version
  • plugins/semanticcache/changelog.md
  • plugins/semanticcache/version
  • plugins/telemetry/changelog.md
  • plugins/telemetry/version
  • tests/docker-compose.yml
  • transports/bifrost-http/handlers/asyncinference.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/lib/ctx.go
  • transports/changelog.md
  • transports/version

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Async jobs now propagate per-request user values (including virtual keys); trace completion callbacks accept transport/plugin logs.
  • Bug Fixes

    • Fixed streaming post-hook race and improved post-hook/error delivery and async-job error handling.
  • Tests

    • Added extensive tests for async context propagation, job lifecycle/failures, migrations, and DB/migration end-to-end coverage; test infra now includes TLS-capable Redis services.
  • Chores

    • Bumped component versions and updated multiple changelogs.

Walkthrough

Async request user-values are propagated into background async job execution: SubmitJob gained a contextValues parameter; the background worker restores those key/value pairs into a new BifrostContext (and sets the async flag) before running the operation. Call sites, tests, and related streaming/middleware plumbing were updated.

Changes

Cohort / File(s) Summary
Async Job Core & Tests
framework/logstore/asyncjob.go, framework/logstore/asyncjob_test.go
SubmitJob and internal executeJob signatures extended to accept contextValues map[any]any; background execution restores provided key/value pairs into a new BifrostContext and forces async flag. New tests validate propagation, nil/empty handling, async flag enforcement, and failure persistence.
Async Handlers & Router
transports/bifrost-http/handlers/asyncinference.go, transports/bifrost-http/integrations/router.go
Async submission handlers and router now pass bifrostCtx.GetUserValues() into SubmitJob. Trace completer signature adapted to accept transport logs and is invoked accordingly in streaming paths.
Streaming Handlers & Middleware
transports/bifrost-http/handlers/inference.go, transports/bifrost-http/handlers/middlewares.go
Fixed streaming post-hook race by publishing completer into an atomic.Value slot, capturing request/response and plugin logs before ctx recycling, added runTransportPostHooksCaptured, and changed trace completer to func([]schemas.PluginLogEntry). Post-hook error/log handling updated.
Context Utilities
transports/bifrost-http/lib/ctx.go
Added BuildHTTPResponseFromFastHTTP(ctx *fasthttp.RequestCtx) *schemas.HTTPResponse to snapshot response status and headers.
Migrations & Migration Tests
framework/configstore/migrations_test.go, .github/workflows/scripts/run-migration-tests.sh
Large migration test additions and in-memory DB harness; targeted migration/backfill tests and updated CI migration script to handle dynamic columns and snapshot comparisons.
Test DB Migration Setup
framework/configstore/rdb_test.go
Added OAuth-related tables to AutoMigrate in test RDB setup.
Redis TLS & Tests / Test Compose
framework/vectorstore/redis_test.go, tests/docker-compose.yml
TLS tests adjusted to read CA from tests/redis-certs; tests skip if CA absent; docker-compose gains services to generate certs and run TLS/cluster Redis instances.
Misc: Context, Changelogs & Versions
core/schemas/bifrost.go, transports/bifrost-http/lib/ctx.go, core/changelog.md, framework/changelog.md, transports/changelog.md, core/version, framework/version, transports/version, multiple plugins/*/changelog.md, plugins/*/version
Doc/comment updates for trace completer signature, added BuildHTTPResponse helper, numerous changelog entries, and version bumps across core, framework, transports, and plugins.
Other
.gitignore, .github/workflows/scripts/run-migration-tests.sh
Added ignore for generated test Redis certs; CI script updated for additional dynamic-column handling and snapshot diffs.

Sequence Diagram

sequenceDiagram
    participant Client as HTTP Client
    participant Handler as Async Handler
    participant Executor as AsyncJobExecutor
    participant Store as LogStore/DB
    participant Worker as Background Worker
    participant Ctx as BifrostContext

    Client->>Handler: HTTP request (with user values)
    Handler->>Executor: SubmitJob(..., contextValues)
    Executor->>Store: Persist async job record
    Store-->>Executor: Job ID
    Executor->>Worker: Schedule background execution (jobID + contextValues)
    Worker->>Ctx: New BifrostContext()
    Worker->>Ctx: Restore each contextValue via SetValue(k,v)
    Worker->>Ctx: Set BifrostIsAsyncRequest = true
    Worker->>Worker: Execute operation using restored context
    Worker->>Store: Update job status / result / error / TTL
    Handler-->>Client: 202 Accepted (job id)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐇
I hopped through keys, one by one, so neat,
From incoming request down to the seat;
In burrowed jobs my values cling,
No context lost while backgrounds spring —
A rabbit's stitch makes async complete.

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'exception fixes' is vague and generic, using a non-descriptive term that does not convey meaningful information about the changeset's primary focus. Consider using a more specific title such as 'Fix context propagation in async job execution' to clearly communicate the main change being addressed.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The PR description is comprehensive and well-structured, addressing all major template sections including summary, changes, type of change, affected areas, testing instructions, and security considerations.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 04-13-exception_fixes

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@akshaydeo akshaydeo marked this pull request as ready for review April 13, 2026 09:56
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 13, 2026

Confidence Score: 4/5

Safe to merge after correcting the three status-code outliers; the core context-propagation and streaming fixes look correct.

The context propagation fix and the streaming ctx-recycling fix are both sound. The one remaining P1 is the wrong HTTP status code returned by asyncTextCompletion, asyncRerank, and asyncOCR for SubmitJob client errors — fixing three lines before merge would make this 5/5.

transports/bifrost-http/handlers/asyncinference.go — lines 134, 471, and 505

Important Files Changed

Filename Overview
framework/logstore/asyncjob.go Context propagation implemented cleanly — restores original request values onto a fresh background BifrostContext and correctly sets BifrostIsAsyncRequest after the restore to prevent override.
framework/logstore/asyncjob_test.go Solid test coverage for context propagation cases (nil, empty, override, failure); previous racy sleep replaced with polling waitForJobStatus helper.
transports/bifrost-http/handlers/asyncinference.go Correctly propagates context values via GetUserValues(); three handlers (asyncTextCompletion, asyncRerank, asyncOCR) incorrectly return 500 for SubmitJob errors that include client-caused failures like "virtual key not found".
transports/bifrost-http/handlers/inference.go Streaming handler now pre-allocates completerSlot before next(ctx), fixing the wiring issue; goroutine polls atomic slot for up to 100 ms twice (pre-DONE and defer), giving middleware ample time to store the completer.
transports/bifrost-http/handlers/middlewares.go New runTransportPostHooksCaptured correctly clones pooled objects to avoid mutating snapshots; deferred streaming path eagerly captures request/response before ctx recycling and stores completer in atomic slot.
transports/bifrost-http/lib/ctx.go New BuildHTTPResponseFromFastHTTP utility correctly snapshots status code and headers without touching the active body stream.

Comments Outside Diff (1)

  1. transports/bifrost-http/handlers/asyncinference.go, line 133-135 (link)

    P1 Incorrect 500 status for client-caused SubmitJob errors

    SubmitJob can return "virtual key not found" — a client error that should be HTTP 400. Returning 500 here gives clients a misleading signal and breaks 4xx/5xx monitoring.

    The same mismatch exists in asyncRerank (line 471) and asyncOCR (line 505). The other eight async handlers in this file all use fasthttp.StatusBadRequest, which is consistent with how the pre-existing handlers treated this error.

Reviews (6): Last reviewed commit: "exception fixes" | Re-trigger Greptile

Comment thread transports/bifrost-http/handlers/middlewares.go
Comment thread framework/logstore/asyncjob_test.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
transports/bifrost-http/handlers/middlewares.go (1)

1018-1026: ⚠️ Potential issue | 🟠 Major

The new trace completer signature is not wired into the streaming handler.

This now stores func([]schemas.PluginLogEntry), but transports/bifrost-http/integrations/router.go still does ctx.UserValue(schemas.BifrostContextKeyTraceCompleter).(func()) at Line 2318 and invokes it with no args. That assertion will fail, so traceCompleter stays nil and streaming traces never flush.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/handlers/middlewares.go` around lines 1018 - 1026,
The trace completer stored with ctx.SetUserValue using
schemas.BifrostContextKeyTraceCompleter now has the signature
func([]schemas.PluginLogEntry) but the streaming handler in
transports/bifrost-http/integrations/router.go still type-asserts and calls it
as func() causing a panic and never flushing traces; update the router streaming
code to type-assert the user value as func([]schemas.PluginLogEntry) (or check
both signatures if backward compatibility is needed) and invoke it with the
transport/plugin logs available in the streaming path (or pass nil when none) so
tracer.AttachPluginLogs and tracer.CompleteAndFlushTrace run as intended.
🧹 Nitpick comments (1)
framework/logstore/asyncjob_test.go (1)

55-55: Use bifrost.Ptr() instead of & for pointer construction.

Please replace strPtr (and direct &value patterns) with bifrost.Ptr(...) to stay consistent with repository conventions in tests too.

Based on learnings: "In the maximhq/bifrost repository, prefer using bifrost.Ptr() to create pointers instead of the address operator (&) even when & would be valid syntactically... including test utilities."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/logstore/asyncjob_test.go` at line 55, The test helper strPtr and
any direct pointer constructions using & (e.g., &value) should be replaced with
bifrost.Ptr(...) to match repo conventions; remove or replace the strPtr
function and update all call sites in asyncjob_test.go (and any other tests) to
call bifrost.Ptr("...") or bifrost.Ptr(variable) instead of strPtr(...) or
&variable so tests use the canonical pointer helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@framework/logstore/asyncjob_test.go`:
- Around line 203-206: Replace the brittle fixed sleep in the test with a
bounded polling loop: use a context with timeout (similar to
waitForJobCompletion) and repeatedly call
executor.logstore.FindAsyncJobByID(ctx, job.ID) until retrievedJob.Status equals
schemas.AsyncJobStatusFailed or the deadline expires, then require.NoError for
the final call and assert the status is Failed; reference the FindAsyncJobByID
call and the waitForJobCompletion pattern to implement the backoff/polling and
timeout behavior.

In `@transports/bifrost-http/handlers/middlewares.go`:
- Around line 360-390: Move the lookup of the completer slot
(schemas.BifrostContextKeyTransportPostHookCompleter) before allocating
capturedReq/capturedResp so you only snapshot when a slot exists; i.e., check
ctx.UserValue(...).(*atomic.Value) first, return/skip work if nil, and only then
call lib.BuildHTTPRequestFromFastHTTP and lib.BuildHTTPResponseFromFastHTTP and
capture preHookLogs; ensure the ReleaseHTTPRequest/ReleaseHTTPResponse calls
remain in the completer closure (or add immediate releases if you early-return
after allocation) and keep runTransportPostHooksCaptured, completer, and
slot.Store(completer) logic unchanged.

---

Outside diff comments:
In `@transports/bifrost-http/handlers/middlewares.go`:
- Around line 1018-1026: The trace completer stored with ctx.SetUserValue using
schemas.BifrostContextKeyTraceCompleter now has the signature
func([]schemas.PluginLogEntry) but the streaming handler in
transports/bifrost-http/integrations/router.go still type-asserts and calls it
as func() causing a panic and never flushing traces; update the router streaming
code to type-assert the user value as func([]schemas.PluginLogEntry) (or check
both signatures if backward compatibility is needed) and invoke it with the
transport/plugin logs available in the streaming path (or pass nil when none) so
tracer.AttachPluginLogs and tracer.CompleteAndFlushTrace run as intended.

---

Nitpick comments:
In `@framework/logstore/asyncjob_test.go`:
- Line 55: The test helper strPtr and any direct pointer constructions using &
(e.g., &value) should be replaced with bifrost.Ptr(...) to match repo
conventions; remove or replace the strPtr function and update all call sites in
asyncjob_test.go (and any other tests) to call bifrost.Ptr("...") or
bifrost.Ptr(variable) instead of strPtr(...) or &variable so tests use the
canonical pointer helper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 621cfce3-a30d-40ff-9e84-3a19bdb25ed9

📥 Commits

Reviewing files that changed from the base of the PR and between ab8973c and 7bd6f79.

📒 Files selected for processing (6)
  • framework/logstore/asyncjob.go
  • framework/logstore/asyncjob_test.go
  • transports/bifrost-http/handlers/asyncinference.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/lib/ctx.go

Comment thread framework/logstore/asyncjob_test.go Outdated
Comment thread framework/logstore/asyncjob.go
Comment thread transports/bifrost-http/handlers/middlewares.go Outdated
@akshaydeo akshaydeo force-pushed the 04-13-exception_fixes branch from 7bd6f79 to 577707d Compare April 13, 2026 10:39
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@transports/bifrost-http/handlers/inference.go`:
- Around line 1699-1711: The post-hook completer (closure-loaded via
completerSlot and invoked as postHookCompleter()) is currently called after the
stream termination and uses reader.SendError to emit errors, which can send
events after the terminal “[DONE]” marker; move the post-hook invocation so it
runs before emitting the final marker (i.e., call the loaded postHookCompleter
and handle its logs/errors prior to the code that writes the final
“[DONE]”/stream-close) and if you cannot move it ensure you do not call
reader.SendError after termination — instead log the error server-side (e.g.,
processLogger or append to transportLogs) so post-hook failures are recorded
without sending late SSE via reader.SendError.
- Around line 1671-1676: The spawned goroutine must not assume completerSlot is
already set; change the goroutine started in the handler to wait for
completerSlot.Load() to return a non-nil value (poll with a short sleep/backoff
and a bounded timeout) before invoking the completer, and log or handle the
timeout case so post-hooks aren’t silently skipped; reference the completerSlot
atomic.Value placed under schemas.BifrostContextKeyTransportPostHookCompleter
and the TransportInterceptorMiddleware behavior (which calls
slot.Store(completer) asynchronously) to locate where to add the wait/poll and
timeout handling.

In `@transports/bifrost-http/handlers/middlewares.go`:
- Around line 1024-1028: The new callback stored under
schemas.BifrostContextKeyTraceCompleter has been changed to type
func([]schemas.PluginLogEntry) but the router-side consumer still asserts and
calls it as func() — update that consumer to assert the new signature and invoke
it with the transport plugin logs; specifically, locate the code that does a
ctx.Value(schemas.BifrostContextKeyTraceCompleter).(func()) (in the router
integration) and change it to assert func([]schemas.PluginLogEntry) and pass the
relevant transportLogs slice when calling so traces are completed/flushed
correctly.
- Around line 469-489: The cloned request used for post-hooks (created via
schemas.AcquireHTTPRequest and assigned to req) doesn't copy the request
payload, so post-hooks using runTransportPostHooks see an empty Body; update the
clone logic that copies capturedReq (the block that sets req.Method, req.Path,
req.Headers, req.Query, req.PathParams) to also copy the body: if
capturedReq.Body is non-nil, produce a safe clone (e.g., duplicate the byte
slice or buffer contents into a new reader/byte slice) and assign it to req.Body
so mutations by hooks won't affect the original, and ensure any
ownership/cleanup expectations of schemas.ReleaseHTTPRequest still hold.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e59c9514-7bd7-4c31-a068-b9ac38834019

📥 Commits

Reviewing files that changed from the base of the PR and between 7bd6f79 and 577707d.

📒 Files selected for processing (35)
  • core/changelog.md
  • core/version
  • framework/changelog.md
  • framework/logstore/asyncjob.go
  • framework/logstore/asyncjob_test.go
  • framework/version
  • plugins/compat/changelog.md
  • plugins/compat/version
  • plugins/governance/changelog.md
  • plugins/governance/version
  • plugins/jsonparser/changelog.md
  • plugins/jsonparser/version
  • plugins/litellmcompat/changelog.md
  • plugins/litellmcompat/version
  • plugins/logging/changelog.md
  • plugins/logging/version
  • plugins/maxim/changelog.md
  • plugins/maxim/version
  • plugins/mocker/changelog.md
  • plugins/mocker/version
  • plugins/otel/changelog.md
  • plugins/otel/version
  • plugins/prompts/changelog.md
  • plugins/prompts/version
  • plugins/semanticcache/changelog.md
  • plugins/semanticcache/version
  • plugins/telemetry/changelog.md
  • plugins/telemetry/version
  • transports/bifrost-http/handlers/asyncinference.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/lib/ctx.go
  • transports/changelog.md
  • transports/version
✅ Files skipped from review due to trivial changes (29)
  • framework/version
  • plugins/litellmcompat/changelog.md
  • plugins/logging/changelog.md
  • plugins/maxim/version
  • core/version
  • plugins/mocker/version
  • plugins/semanticcache/changelog.md
  • plugins/governance/changelog.md
  • plugins/otel/changelog.md
  • plugins/telemetry/changelog.md
  • plugins/prompts/changelog.md
  • plugins/governance/version
  • plugins/prompts/version
  • plugins/jsonparser/version
  • plugins/logging/version
  • plugins/jsonparser/changelog.md
  • plugins/otel/version
  • transports/version
  • plugins/compat/version
  • plugins/semanticcache/version
  • plugins/litellmcompat/version
  • plugins/mocker/changelog.md
  • framework/changelog.md
  • plugins/telemetry/version
  • transports/changelog.md
  • core/changelog.md
  • plugins/compat/changelog.md
  • plugins/maxim/changelog.md
  • framework/logstore/asyncjob_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/handlers/asyncinference.go
  • framework/logstore/asyncjob.go

Comment thread transports/bifrost-http/handlers/inference.go
Comment thread transports/bifrost-http/handlers/inference.go Outdated
Comment thread transports/bifrost-http/handlers/middlewares.go
Comment thread transports/bifrost-http/handlers/middlewares.go
@akshaydeo akshaydeo force-pushed the 04-13-exception_fixes branch from 577707d to cc97b6d Compare April 13, 2026 12:07
@akshaydeo
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Pushed fixes for the 4 unresolved threads from the previous review:

  • 3072425551 — race on completerSlot → added bounded 100ms poll in inference.go runCompleter closure
  • 3072425564 — SSE error after [DONE] → completer now runs before reader.SendDone() on happy path; defer fallback logs server-side only
  • 3072425566 — captured body copy → left as-is by design (snapshots intentionally skip body; fasthttp SetBodyStream forbids reading response body; no post-hook plugin reads body)
  • 3072425594 — router.go trace completer signature drift → fixed type assertion + updated schema doc comment in core/schemas/bifrost.go:215

Please re-review and resolve the threads if satisfied.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

@akshaydeo Thanks for the detailed summary of the fixes! I'll kick off a fresh review to verify the changes and resolve the threads if the fixes look good.

✅ Actions performed

Full review triggered.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
transports/bifrost-http/handlers/inference.go (1)

1704-1729: ⚠️ Potential issue | 🟠 Major

Only mark the completer as executed after you've actually obtained it.

On Line 1708, completerRan is set before completerSlot.Load() succeeds. If the 100ms wait expires and Line 1724 returns with loaded == nil, the deferred runCompleter(false) path becomes a no-op, so transport post-hooks and their trace logs are still silently skipped on the timeout path. It also leaves the captured HTTPRequest / HTTPResponse snapshots allocated in transports/bifrost-http/handlers/middlewares.go unreleased, since their Release* calls only happen inside the completer closure.

Suggested fix
 runCompleter := func(sendSSEOnError bool) {
 	if completerRan {
 		return
 	}
-	completerRan = true
 	// Bounded wait for TransportInterceptorMiddleware to publish the completer.
 	var loaded any
 	deadline := time.Now().Add(100 * time.Millisecond)
 	for {
 		if loaded = completerSlot.Load(); loaded != nil {
@@
 	if loaded == nil {
 		return
 	}
 	postHookCompleter, ok := loaded.(func() ([]schemas.PluginLogEntry, error))
 	if !ok {
 		return
 	}
+	completerRan = true
 	logs, err := postHookCompleter()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/handlers/inference.go` around lines 1704 - 1729, Move
the completerRan = true assignment so it only happens after you successfully
load and type-assert the completer from completerSlot; specifically, in
runCompleter, do not set completerRan before calling completerSlot.Load() and
validating loaded != nil and ok == true for postHookCompleter, instead set
completerRan = true immediately after the type assertion succeeds (i.e., after
confirming postHookCompleter is a valid func() ([]schemas.PluginLogEntry,
error)) so the deferred runCompleter(false) path still runs the completer on
timeout and releases any captured HTTPRequest/HTTPResponse snapshots.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@framework/configstore/migrations_test.go`:
- Around line 1169-1189: The TestTriggerMigrations_Idempotent test opens sqlite
":memory:" directly which can create multiple isolated in-memory DBs when
connections are reset by triggerMigrations (it calls SetMaxOpenConns(0));
replace the direct gorm.Open setup with the helper setupFullMigrationDB(t) so
the test uses a single pinned connection for all operations, invoke
triggerMigrations(ctx, db) twice as before, and keep the same
db.Migrator().HasTable(...) assertions against that db to verify idempotency.

---

Duplicate comments:
In `@transports/bifrost-http/handlers/inference.go`:
- Around line 1704-1729: Move the completerRan = true assignment so it only
happens after you successfully load and type-assert the completer from
completerSlot; specifically, in runCompleter, do not set completerRan before
calling completerSlot.Load() and validating loaded != nil and ok == true for
postHookCompleter, instead set completerRan = true immediately after the type
assertion succeeds (i.e., after confirming postHookCompleter is a valid func()
([]schemas.PluginLogEntry, error)) so the deferred runCompleter(false) path
still runs the completer on timeout and releases any captured
HTTPRequest/HTTPResponse snapshots.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 180cfc36-677d-4ffd-b5fb-3b9077b1fa50

📥 Commits

Reviewing files that changed from the base of the PR and between 577707d and cc97b6d.

📒 Files selected for processing (37)
  • core/changelog.md
  • core/schemas/bifrost.go
  • core/version
  • framework/changelog.md
  • framework/configstore/migrations_test.go
  • framework/logstore/asyncjob.go
  • framework/logstore/asyncjob_test.go
  • framework/version
  • plugins/compat/changelog.md
  • plugins/compat/version
  • plugins/governance/changelog.md
  • plugins/governance/version
  • plugins/jsonparser/changelog.md
  • plugins/jsonparser/version
  • plugins/litellmcompat/changelog.md
  • plugins/litellmcompat/version
  • plugins/logging/changelog.md
  • plugins/logging/version
  • plugins/maxim/changelog.md
  • plugins/maxim/version
  • plugins/mocker/changelog.md
  • plugins/mocker/version
  • plugins/otel/changelog.md
  • plugins/otel/version
  • plugins/prompts/changelog.md
  • plugins/prompts/version
  • plugins/semanticcache/changelog.md
  • plugins/semanticcache/version
  • plugins/telemetry/changelog.md
  • plugins/telemetry/version
  • transports/bifrost-http/handlers/asyncinference.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/lib/ctx.go
  • transports/changelog.md
  • transports/version
✅ Files skipped from review due to trivial changes (27)
  • plugins/telemetry/changelog.md
  • plugins/semanticcache/changelog.md
  • plugins/mocker/changelog.md
  • plugins/jsonparser/changelog.md
  • plugins/maxim/version
  • plugins/governance/changelog.md
  • plugins/mocker/version
  • plugins/jsonparser/version
  • plugins/prompts/changelog.md
  • plugins/logging/version
  • framework/version
  • plugins/logging/changelog.md
  • plugins/compat/version
  • framework/changelog.md
  • plugins/otel/version
  • plugins/prompts/version
  • plugins/maxim/changelog.md
  • plugins/otel/changelog.md
  • transports/version
  • plugins/compat/changelog.md
  • plugins/litellmcompat/version
  • plugins/governance/version
  • plugins/telemetry/version
  • plugins/litellmcompat/changelog.md
  • transports/changelog.md
  • framework/logstore/asyncjob_test.go
  • plugins/semanticcache/version
🚧 Files skipped from review as they are similar to previous changes (5)
  • core/version
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/handlers/asyncinference.go
  • framework/logstore/asyncjob.go
  • core/changelog.md

Comment thread framework/configstore/migrations_test.go
@akshaydeo akshaydeo force-pushed the 04-13-exception_fixes branch from cc97b6d to 75cc3f2 Compare April 13, 2026 12:17
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
transports/bifrost-http/integrations/router.go (1)

2317-2345: ⚠️ Potential issue | 🟠 Major

Run the captured transport post-hooks before completing the trace.

transports/bifrost-http/handlers/middlewares.go:360-405 now stores a deferred transport-post-hook completer for streaming responses, but this goroutine still hardcodes traceCompleter(nil). GenericRouter streams will therefore complete traces without ever invoking the captured post-hooks or attaching their plugin logs. This path should mirror the async streaming handler: run the stored completer in the goroutine and pass its logs into traceCompleter.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/integrations/router.go` around lines 2317 - 2345, The
goroutine currently calls traceCompleter(nil) and thus skips the deferred
transport post-hook completer stored by the middleware; retrieve the stored
transport-post-hook completer from the request context (the same UserValue key
used by transports/bifrost-http/handlers/middlewares.go), run that completer
inside the goroutine before completing the trace, capture its returned plugin
logs and pass them into traceCompleter (i.e. call
transportPostHookCompleter(...) to get []schemas.PluginLogEntry and then call
traceCompleter(logs)); update the defer block where traceCompleter(nil) is
invoked (near reader.Done, schemas.ReleaseHTTPRequest) to run the transport
completer and forward its logs to traceCompleter so plugin logs are attached to
the trace.
♻️ Duplicate comments (1)
framework/configstore/migrations_test.go (1)

1169-1189: ⚠️ Potential issue | 🟠 Major

Reuse setupFullMigrationDB() in the idempotency test.

This test still opens :memory: directly, so once triggerMigrations() resets SQLite’s pool settings, the second run and the HasTable assertions can land on a different empty in-memory database. That makes the idempotency check flaky and can hide real migration regressions.

💡 Suggested fix
 func TestTriggerMigrations_Idempotent(t *testing.T) {
-	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
-		Logger: logger.Default.LogMode(logger.Silent),
-	})
-	require.NoError(t, err)
-
+	_, db := setupFullMigrationDB(t)
 	ctx := context.Background()
 
-	// First run
-	err = triggerMigrations(ctx, db)
-	require.NoError(t, err, "first triggerMigrations should succeed")
-
-	// Second run – must be a no-op, not an error.
-	err = triggerMigrations(ctx, db)
+	// Second run – must be a no-op, not an error.
+	err := triggerMigrations(ctx, db)
 	require.NoError(t, err, "second triggerMigrations should succeed (idempotent)")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations_test.go` around lines 1169 - 1189, Replace
the direct in-memory sqlite gorm.Open in TestTriggerMigrations_Idempotent with
the shared helper setupFullMigrationDB() so the test reuses the same DB
connection/pool used by other migration tests; specifically, remove the
sqlite.Open(":memory:")/gorm.Open block and call setupFullMigrationDB(ctx) to
obtain db (and handle its returned error) before calling triggerMigrations(ctx,
db) twice and running the HasTable assertions on tables.TableProvider,
tables.TableKey, and tables.TableVirtualKey.
🧹 Nitpick comments (1)
framework/logstore/asyncjob_test.go (1)

85-114: Add a post-submit mutation case for contextValues.

This only proves propagation of a stable map literal. It won’t catch a bug where SubmitJob retains the caller’s contextValues map by reference, which would let later request-context mutations leak the wrong virtual key or tracing metadata into the background job. Add a case that mutates the original map after SubmitJob returns and assert the async callback still sees the original values.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/logstore/asyncjob_test.go` around lines 85 - 114, Add a post-submit
mutation test to ensure SubmitJob copies contextValues rather than retaining the
map by reference: after calling executor.SubmitJob in
TestSubmitJob_PropagatesContextValues, mutate the original contextValues map
(e.g., change the value for schemas.BifrostContextKeyVirtualKey and add/modify
other keys) immediately after SubmitJob returns, then waitForJobCompletion and
assert that the capturedCtx (from the operation closure) still sees the original
values (referencing capturedCtx, executor.SubmitJob, waitForJobCompletion, and
done) to verify SubmitJob made a defensive copy.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@framework/changelog.md`:
- Around line 1-4: Update the changelog bullets to explicitly list the PR’s
primary fixes: add an entry for "fix: restore async context values correctly
(async context value restoration)", an entry for "fix: make streaming
fasthttp.RequestCtx snapshots safe (streaming RequestCtx snapshot safety)", and
an entry for "change: trace completion callback now receives (context, error) or
updated input signature (trace completion callback input change)"; place these
lines alongside the existing bullets (refer to the current changelog entries and
add the three new lines so release notes accurately reflect fixes to async
context restoration, fasthttp.RequestCtx snapshot safety, and the trace
completion callback input change).

In `@plugins/prompts/version`:
- Line 1: The version file for the prompts plugin was bumped to 1.0.2 without
any corresponding code changes; either revert the file back to 1.0.1 or include
the actual functional changes and tests that justify the bump. If you choose to
keep 1.0.2, update the prompts plugin source (e.g., main.go) and any relevant
tests (helpers_test.go, plugin_test.go) to reflect the new behavior, and
add/update a brief changelog entry; if you revert, change the version file back
to 1.0.1 and ensure no other references to 1.0.2 remain.

In `@transports/bifrost-http/handlers/inference.go`:
- Around line 1704-1726: The issue is that completerRan is set to true before we
actually acquire the completer from completerSlot, which can make the fallback a
no-op if the slot remains empty; in runCompleter change the logic so you only
set completerRan = true after successfully loading a non-nil value from
completerSlot (i.e., move the completerRan assignment to immediately after the
loaded != nil check/return), keeping the existing 100ms wait loop and behavior
around sendSSEOnError; reference completerRan, runCompleter, completerSlot.Load
and sendSSEOnError when making the change.

In `@transports/bifrost-http/integrations/router.go`:
- Line 1507: Currently bifrostCtx.GetUserValues() passes the entire user-values
map into executor.SubmitJob(vkValue, resultTTL, operation, operationType,
bifrostCtx.GetUserValues()), which lets transport-internal fasthttp keys (e.g.,
FastHTTPUserValueBifrostContext, FastHTTPUserValueBifrostCancel,
FastHTTPUserValueLargeResponseMode) propagate into executeJob(); instead, build
and pass a filtered allowlist map containing only safe values (e.g., virtual key
and tracing headers) before calling executor.SubmitJob, and update the call-site
so executeJob receives only that allowlisted map rather than the full
bifrostCtx.GetUserValues() output.

---

Outside diff comments:
In `@transports/bifrost-http/integrations/router.go`:
- Around line 2317-2345: The goroutine currently calls traceCompleter(nil) and
thus skips the deferred transport post-hook completer stored by the middleware;
retrieve the stored transport-post-hook completer from the request context (the
same UserValue key used by transports/bifrost-http/handlers/middlewares.go), run
that completer inside the goroutine before completing the trace, capture its
returned plugin logs and pass them into traceCompleter (i.e. call
transportPostHookCompleter(...) to get []schemas.PluginLogEntry and then call
traceCompleter(logs)); update the defer block where traceCompleter(nil) is
invoked (near reader.Done, schemas.ReleaseHTTPRequest) to run the transport
completer and forward its logs to traceCompleter so plugin logs are attached to
the trace.

---

Duplicate comments:
In `@framework/configstore/migrations_test.go`:
- Around line 1169-1189: Replace the direct in-memory sqlite gorm.Open in
TestTriggerMigrations_Idempotent with the shared helper setupFullMigrationDB()
so the test reuses the same DB connection/pool used by other migration tests;
specifically, remove the sqlite.Open(":memory:")/gorm.Open block and call
setupFullMigrationDB(ctx) to obtain db (and handle its returned error) before
calling triggerMigrations(ctx, db) twice and running the HasTable assertions on
tables.TableProvider, tables.TableKey, and tables.TableVirtualKey.

---

Nitpick comments:
In `@framework/logstore/asyncjob_test.go`:
- Around line 85-114: Add a post-submit mutation test to ensure SubmitJob copies
contextValues rather than retaining the map by reference: after calling
executor.SubmitJob in TestSubmitJob_PropagatesContextValues, mutate the original
contextValues map (e.g., change the value for
schemas.BifrostContextKeyVirtualKey and add/modify other keys) immediately after
SubmitJob returns, then waitForJobCompletion and assert that the capturedCtx
(from the operation closure) still sees the original values (referencing
capturedCtx, executor.SubmitJob, waitForJobCompletion, and done) to verify
SubmitJob made a defensive copy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3a0826b9-90f3-4bc2-b273-5a303ea0dc64

📥 Commits

Reviewing files that changed from the base of the PR and between 762f897 and cc97b6d.

📒 Files selected for processing (37)
  • core/changelog.md
  • core/schemas/bifrost.go
  • core/version
  • framework/changelog.md
  • framework/configstore/migrations_test.go
  • framework/logstore/asyncjob.go
  • framework/logstore/asyncjob_test.go
  • framework/version
  • plugins/compat/changelog.md
  • plugins/compat/version
  • plugins/governance/changelog.md
  • plugins/governance/version
  • plugins/jsonparser/changelog.md
  • plugins/jsonparser/version
  • plugins/litellmcompat/changelog.md
  • plugins/litellmcompat/version
  • plugins/logging/changelog.md
  • plugins/logging/version
  • plugins/maxim/changelog.md
  • plugins/maxim/version
  • plugins/mocker/changelog.md
  • plugins/mocker/version
  • plugins/otel/changelog.md
  • plugins/otel/version
  • plugins/prompts/changelog.md
  • plugins/prompts/version
  • plugins/semanticcache/changelog.md
  • plugins/semanticcache/version
  • plugins/telemetry/changelog.md
  • plugins/telemetry/version
  • transports/bifrost-http/handlers/asyncinference.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/lib/ctx.go
  • transports/changelog.md
  • transports/version

Comment thread framework/changelog.md
Comment thread plugins/prompts/version
Comment thread transports/bifrost-http/handlers/inference.go
Comment thread transports/bifrost-http/integrations/router.go
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (3)
framework/configstore/migrations_test.go (1)

1166-1186: ⚠️ Potential issue | 🟠 Major

Use setupFullMigrationDB in idempotency test to avoid SQLite :memory: connection flakiness.

Line 1167 reintroduces direct sqlite.Open(":memory:"). This can make the second migration/assertion path non-deterministic when connection settings change during migration flow. Please reuse the shared-cache helper here.

Suggested fix
 func TestTriggerMigrations_Idempotent(t *testing.T) {
-	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
-		Logger: logger.Default.LogMode(logger.Silent),
-	})
-	require.NoError(t, err)
-
+	_, db := setupFullMigrationDB(t)
 	ctx := context.Background()
 
-	// First run
-	err = triggerMigrations(ctx, db)
-	require.NoError(t, err, "first triggerMigrations should succeed")
-
-	// Second run – must be a no-op, not an error.
-	err = triggerMigrations(ctx, db)
+	// setupFullMigrationDB already performs the first run.
+	// Run once more to verify idempotency.
+	err := triggerMigrations(ctx, db)
 	require.NoError(t, err, "second triggerMigrations should succeed (idempotent)")
 
 	// Tables should still be intact
 	assert.True(t, db.Migrator().HasTable(&tables.TableProvider{}), "TableProvider should still exist")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations_test.go` around lines 1166 - 1186, The test
TestTriggerMigrations_Idempotent currently opens a raw in-memory SQLite via
sqlite.Open(":memory:") which can be flaky; replace that setup with the shared
helper setupFullMigrationDB so the test uses the stable shared-cache DB. Call
setupFullMigrationDB to obtain the *gorm.DB (and context if returned), check for
errors with require.NoError, then run triggerMigrations twice and assert the
same tables (tables.TableProvider, tables.TableKey, tables.TableVirtualKey)
still exist; keep the existing assertions and messages but remove the direct
sqlite.Open usage.
transports/bifrost-http/handlers/asyncinference.go (1)

124-132: ⚠️ Potential issue | 🟠 Major

Apply the same async-context allowlist here instead of GetUserValues().

All of these handlers now pass the full request-scoped user-values map into background execution. That replays the same transient transport state as the router path. Please route these through a shared allowlist helper so every async endpoint propagates only the intended keys.

🧩 Suggested direction
-		bifrostCtx.GetUserValues(),
+		buildAsyncContextValues(bifrostCtx),

Based on learnings, governance context keys in Go propagation are limited to VirtualKey, Team, Customer, User, RoutingRule, IncludeOnlyKeys, and PluginName.

Also applies to: 163-171, 202-210, 237-245, 276-284, 315-323, 354-362, 393-401, 427-435, 461-469, 495-503

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/handlers/asyncinference.go` around lines 124 - 132,
Replace the direct use of bifrostCtx.GetUserValues() when calling
h.executor.SubmitJob with the shared async-context allowlist helper so only
allowed governance keys are propagated; specifically, change the SubmitJob call
site that passes bifrostCtx.GetUserValues() (the call that wraps
h.client.TextCompletionRequest) to instead pass the result of the allowlist
helper (e.g., ApplyAsyncContextAllowlist or similar), ensuring the helper
filters for only VirtualKey, Team, Customer, User, RoutingRule, IncludeOnlyKeys
and PluginName before handing values to SubmitJob; do the same replacement for
the other similar SubmitJob sites mentioned.
transports/bifrost-http/integrations/router.go (1)

1507-1507: ⚠️ Potential issue | 🟠 Major

Don't pass the full request user-values map into async jobs.

GetUserValues() is broader than the async worker should inherit. Passing it through verbatim here can keep transport-only callbacks/pointers alive after the request ends. Please build an explicit allowlist snapshot for async-safe keys and pass that instead.

🧩 Suggested direction
-	job, err := executor.SubmitJob(vkValue, resultTTL, operation, operationType, bifrostCtx.GetUserValues())
+	job, err := executor.SubmitJob(vkValue, resultTTL, operation, operationType, buildAsyncContextValues(bifrostCtx))

Based on learnings, governance context keys in Go propagation are limited to VirtualKey, Team, Customer, User, RoutingRule, IncludeOnlyKeys, and PluginName.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@transports/bifrost-http/integrations/router.go` at line 1507, The code
currently passes the entire request user-values map from
bifrostCtx.GetUserValues() into executor.SubmitJob which can leak transport-only
callbacks; instead, create an explicit allowlist snapshot map containing only
the async-safe governance keys (VirtualKey, Team, Customer, User, RoutingRule,
IncludeOnlyKeys, PluginName) pulled from bifrostCtx.GetUserValues(), and pass
that snapshot to executor.SubmitJob (replace the GetUserValues() argument with
your new map) so only those whitelisted values are propagated to the async
worker.
🧹 Nitpick comments (1)
framework/logstore/asyncjob.go (1)

114-126: Snapshot contextValues before starting the worker.

SubmitJob passes the caller's map reference straight into a goroutine. If a future caller mutates or reuses that map after SubmitJob returns, executeJob can race while iterating it. Take a shallow copy here so the executor owns an immutable snapshot.

♻️ Suggested change
-	go e.executeJob(job.ID, job.ResultTTL, operation, contextValues)
+	var contextValuesSnapshot map[any]any
+	if len(contextValues) > 0 {
+		contextValuesSnapshot = make(map[any]any, len(contextValues))
+		for k, v := range contextValues {
+			contextValuesSnapshot[k] = v
+		}
+	}
+
+	go e.executeJob(job.ID, job.ResultTTL, operation, contextValuesSnapshot)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/logstore/asyncjob.go` around lines 114 - 126, SubmitJob is passing
the caller's contextValues map by reference into a goroutine, causing a race if
the caller mutates the map; to fix, take a shallow copy of the contextValues map
before spawning the worker (i.e., before the go e.executeJob(...) call) so the
background worker owns an immutable snapshot; create a new map[any]any, copy all
k,v pairs from the original contextValues into it, and pass that copy into
executeJob (alternatively, perform the same shallow-copy at the start of
executeJob) to eliminate concurrent iteration/mutation races.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@transports/bifrost-http/handlers/middlewares.go`:
- Around line 500-505: The error wrap introduced in the HTTPTransportPostHook
error path uses an uppercase prefix; update the fmt.Errorf call in the post-hook
error branch so the new prefix is lowercase (e.g., "httpTransportPostHook plugin
%s: %w" or similar lowercase wording) to follow Go error string
conventions—locate the error construction near HTTPTransportPostHook handling
where pluginName, bifrostCtx.DrainPluginLogs(), and allLogs are used and replace
the current fmt.Errorf("HTTPTransportPostHook plugin %s: %w", pluginName, err)
with the same text but starting lowercase.
- Around line 382-390: Fix two issues in runTransportPostHooksCaptured: 1)
change the error construction string to start lowercase (e.g., replace
fmt.Errorf("HTTPTransportPostHook plugin %s: %w", ...) with a lowercase prefix
like "transport post-hook plugin %s: %w") so it follows Go error-string
conventions; 2) avoid delegating to the recycled parent context from the
deferred completer by snapshotting any user/context values needed by post-hooks
at defer time (capture them into local variables such as preHookLogs and any
specific keys), or create a fresh context without the original parent (e.g., use
context.Background() with copied values) before calling
runTransportPostHooksCaptured from the completer, and add a short comment near
completer/runTransportPostHooksCaptured/WithPluginScope noting that plugins must
not rely on values from the recycled request context if you choose to document
instead of snapshotting.

---

Duplicate comments:
In `@framework/configstore/migrations_test.go`:
- Around line 1166-1186: The test TestTriggerMigrations_Idempotent currently
opens a raw in-memory SQLite via sqlite.Open(":memory:") which can be flaky;
replace that setup with the shared helper setupFullMigrationDB so the test uses
the stable shared-cache DB. Call setupFullMigrationDB to obtain the *gorm.DB
(and context if returned), check for errors with require.NoError, then run
triggerMigrations twice and assert the same tables (tables.TableProvider,
tables.TableKey, tables.TableVirtualKey) still exist; keep the existing
assertions and messages but remove the direct sqlite.Open usage.

In `@transports/bifrost-http/handlers/asyncinference.go`:
- Around line 124-132: Replace the direct use of bifrostCtx.GetUserValues() when
calling h.executor.SubmitJob with the shared async-context allowlist helper so
only allowed governance keys are propagated; specifically, change the SubmitJob
call site that passes bifrostCtx.GetUserValues() (the call that wraps
h.client.TextCompletionRequest) to instead pass the result of the allowlist
helper (e.g., ApplyAsyncContextAllowlist or similar), ensuring the helper
filters for only VirtualKey, Team, Customer, User, RoutingRule, IncludeOnlyKeys
and PluginName before handing values to SubmitJob; do the same replacement for
the other similar SubmitJob sites mentioned.

In `@transports/bifrost-http/integrations/router.go`:
- Line 1507: The code currently passes the entire request user-values map from
bifrostCtx.GetUserValues() into executor.SubmitJob which can leak transport-only
callbacks; instead, create an explicit allowlist snapshot map containing only
the async-safe governance keys (VirtualKey, Team, Customer, User, RoutingRule,
IncludeOnlyKeys, PluginName) pulled from bifrostCtx.GetUserValues(), and pass
that snapshot to executor.SubmitJob (replace the GetUserValues() argument with
your new map) so only those whitelisted values are propagated to the async
worker.

---

Nitpick comments:
In `@framework/logstore/asyncjob.go`:
- Around line 114-126: SubmitJob is passing the caller's contextValues map by
reference into a goroutine, causing a race if the caller mutates the map; to
fix, take a shallow copy of the contextValues map before spawning the worker
(i.e., before the go e.executeJob(...) call) so the background worker owns an
immutable snapshot; create a new map[any]any, copy all k,v pairs from the
original contextValues into it, and pass that copy into executeJob
(alternatively, perform the same shallow-copy at the start of executeJob) to
eliminate concurrent iteration/mutation races.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 23f19cd8-a531-4f45-9b9e-59bfd2491baf

📥 Commits

Reviewing files that changed from the base of the PR and between cc97b6d and 75cc3f2.

📒 Files selected for processing (38)
  • core/changelog.md
  • core/schemas/bifrost.go
  • core/version
  • framework/changelog.md
  • framework/configstore/migrations_test.go
  • framework/configstore/rdb_test.go
  • framework/logstore/asyncjob.go
  • framework/logstore/asyncjob_test.go
  • framework/version
  • plugins/compat/changelog.md
  • plugins/compat/version
  • plugins/governance/changelog.md
  • plugins/governance/version
  • plugins/jsonparser/changelog.md
  • plugins/jsonparser/version
  • plugins/litellmcompat/changelog.md
  • plugins/litellmcompat/version
  • plugins/logging/changelog.md
  • plugins/logging/version
  • plugins/maxim/changelog.md
  • plugins/maxim/version
  • plugins/mocker/changelog.md
  • plugins/mocker/version
  • plugins/otel/changelog.md
  • plugins/otel/version
  • plugins/prompts/changelog.md
  • plugins/prompts/version
  • plugins/semanticcache/changelog.md
  • plugins/semanticcache/version
  • plugins/telemetry/changelog.md
  • plugins/telemetry/version
  • transports/bifrost-http/handlers/asyncinference.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/lib/ctx.go
  • transports/changelog.md
  • transports/version
✅ Files skipped from review due to trivial changes (29)
  • plugins/maxim/version
  • plugins/logging/changelog.md
  • plugins/otel/version
  • plugins/semanticcache/changelog.md
  • plugins/logging/version
  • plugins/maxim/changelog.md
  • plugins/compat/version
  • plugins/mocker/version
  • plugins/telemetry/changelog.md
  • plugins/prompts/version
  • plugins/litellmcompat/changelog.md
  • framework/changelog.md
  • plugins/governance/changelog.md
  • plugins/jsonparser/changelog.md
  • plugins/telemetry/version
  • plugins/governance/version
  • framework/version
  • plugins/litellmcompat/version
  • plugins/jsonparser/version
  • core/changelog.md
  • core/version
  • plugins/otel/changelog.md
  • plugins/compat/changelog.md
  • plugins/prompts/changelog.md
  • transports/version
  • plugins/semanticcache/version
  • transports/changelog.md
  • plugins/mocker/changelog.md
  • framework/logstore/asyncjob_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • core/schemas/bifrost.go
  • transports/bifrost-http/lib/ctx.go
  • transports/bifrost-http/handlers/inference.go

Comment thread transports/bifrost-http/handlers/middlewares.go
Comment thread transports/bifrost-http/handlers/middlewares.go Outdated
@akshaydeo akshaydeo force-pushed the 04-13-exception_fixes branch from 75cc3f2 to 9a7503d Compare April 13, 2026 13:43
@akshaydeo akshaydeo requested a review from a team as a code owner April 13, 2026 13:43
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
framework/configstore/migrations_test.go (1)

1166-1186: ⚠️ Potential issue | 🟠 Major

Reuse the shared-cache helper here.

Line 1167 still opens SQLite with :memory: directly. After triggerMigrations() relaxes the pool settings, the rerun and HasTable checks can land on a different empty in-memory database, so this idempotency test stays flaky.

Suggested change
 func TestTriggerMigrations_Idempotent(t *testing.T) {
-	db, err := gorm.Open(sqlite.Open(":memory:"), &gorm.Config{
-		Logger: logger.Default.LogMode(logger.Silent),
-	})
-	require.NoError(t, err)
-
+	_, db := setupFullMigrationDB(t)
 	ctx := context.Background()
 
-	// First run
-	err = triggerMigrations(ctx, db)
-	require.NoError(t, err, "first triggerMigrations should succeed")
-
-	// Second run – must be a no-op, not an error.
-	err = triggerMigrations(ctx, db)
-	require.NoError(t, err, "second triggerMigrations should succeed (idempotent)")
+	// Re-run on the same shared in-memory DB.
+	err := triggerMigrations(ctx, db)
+	require.NoError(t, err, "triggerMigrations should succeed when rerun")
 
 	// Tables should still be intact
 	assert.True(t, db.Migrator().HasTable(&tables.TableProvider{}), "TableProvider should still exist")
 	assert.True(t, db.Migrator().HasTable(&tables.TableKey{}), "TableKey should still exist")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/configstore/migrations_test.go` around lines 1166 - 1186,
TestTriggerMigrations_Idempotent opens SQLite with ":memory:" which can produce
different in-memory databases across connections; replace that direct
sqlite.Open(":memory:") usage with the shared-cache helper used elsewhere for
tests (the helper that returns a gorm DB configured for shared-cache in-memory
DB) so both triggerMigrations(ctx, db) runs and subsequent
db.Migrator().HasTable checks operate on the same in-memory database; update the
DB creation in TestTriggerMigrations_Idempotent to call that shared-cache helper
instead of sqlite.Open(":memory:") and keep the rest of the test the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@framework/configstore/migrations_test.go`:
- Around line 1978-2003: Add an assertion that the legacy column
enable_litellm_fallbacks was removed after migration: after the existing mgr :=
db.Migrator() block (or before verifying row contents) call mgr.HasColumn for
the config client struct (tables.TableClientConfig) and assert it returns false
for "enable_litellm_fallbacks" (or otherwise query the DB schema to ensure that
column is absent) so the test fails if the old column remains.

---

Duplicate comments:
In `@framework/configstore/migrations_test.go`:
- Around line 1166-1186: TestTriggerMigrations_Idempotent opens SQLite with
":memory:" which can produce different in-memory databases across connections;
replace that direct sqlite.Open(":memory:") usage with the shared-cache helper
used elsewhere for tests (the helper that returns a gorm DB configured for
shared-cache in-memory DB) so both triggerMigrations(ctx, db) runs and
subsequent db.Migrator().HasTable checks operate on the same in-memory database;
update the DB creation in TestTriggerMigrations_Idempotent to call that
shared-cache helper instead of sqlite.Open(":memory:") and keep the rest of the
test the same.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fd519438-2bec-43f2-969b-682fce68204f

📥 Commits

Reviewing files that changed from the base of the PR and between 75cc3f2 and 9a7503d.

📒 Files selected for processing (39)
  • .github/workflows/scripts/run-migration-tests.sh
  • core/changelog.md
  • core/schemas/bifrost.go
  • core/version
  • framework/changelog.md
  • framework/configstore/migrations_test.go
  • framework/configstore/rdb_test.go
  • framework/logstore/asyncjob.go
  • framework/logstore/asyncjob_test.go
  • framework/version
  • plugins/compat/changelog.md
  • plugins/compat/version
  • plugins/governance/changelog.md
  • plugins/governance/version
  • plugins/jsonparser/changelog.md
  • plugins/jsonparser/version
  • plugins/litellmcompat/changelog.md
  • plugins/litellmcompat/version
  • plugins/logging/changelog.md
  • plugins/logging/version
  • plugins/maxim/changelog.md
  • plugins/maxim/version
  • plugins/mocker/changelog.md
  • plugins/mocker/version
  • plugins/otel/changelog.md
  • plugins/otel/version
  • plugins/prompts/changelog.md
  • plugins/prompts/version
  • plugins/semanticcache/changelog.md
  • plugins/semanticcache/version
  • plugins/telemetry/changelog.md
  • plugins/telemetry/version
  • transports/bifrost-http/handlers/asyncinference.go
  • transports/bifrost-http/handlers/inference.go
  • transports/bifrost-http/handlers/middlewares.go
  • transports/bifrost-http/integrations/router.go
  • transports/bifrost-http/lib/ctx.go
  • transports/changelog.md
  • transports/version
✅ Files skipped from review due to trivial changes (26)
  • plugins/otel/changelog.md
  • plugins/maxim/version
  • plugins/jsonparser/version
  • plugins/compat/version
  • plugins/mocker/version
  • plugins/litellmcompat/version
  • plugins/prompts/changelog.md
  • plugins/governance/changelog.md
  • plugins/governance/version
  • plugins/telemetry/version
  • plugins/semanticcache/version
  • plugins/logging/changelog.md
  • plugins/jsonparser/changelog.md
  • plugins/mocker/changelog.md
  • plugins/prompts/version
  • plugins/litellmcompat/changelog.md
  • plugins/telemetry/changelog.md
  • plugins/otel/version
  • plugins/logging/version
  • plugins/semanticcache/changelog.md
  • core/changelog.md
  • plugins/compat/changelog.md
  • plugins/maxim/changelog.md
  • framework/changelog.md
  • framework/logstore/asyncjob_test.go
  • transports/bifrost-http/handlers/inference.go
🚧 Files skipped from review as they are similar to previous changes (9)
  • core/version
  • framework/version
  • transports/version
  • framework/configstore/rdb_test.go
  • core/schemas/bifrost.go
  • transports/changelog.md
  • transports/bifrost-http/handlers/asyncinference.go
  • framework/logstore/asyncjob.go
  • transports/bifrost-http/handlers/middlewares.go

Comment thread framework/configstore/migrations_test.go
@akshaydeo akshaydeo force-pushed the 04-13-exception_fixes branch from 9a7503d to b208b52 Compare April 13, 2026 14:44
@akshaydeo akshaydeo merged commit e9d467f into v1.5.0 Apr 13, 2026
15 of 18 checks passed
@akshaydeo akshaydeo deleted the 04-13-exception_fixes branch April 13, 2026 14:52
@coderabbitai coderabbitai Bot mentioned this pull request Apr 17, 2026
18 tasks
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.

2 participants