Skip to content

fix(responses): recover LiteLLM-wrapped encrypted content errors - #5245

Closed
cmdy wants to merge 3 commits into
lidge-jun:devfrom
cmdy:cmdy/fix-litellm-encrypted-content
Closed

cmdy wants to merge 3 commits into
lidge-jun:devfrom
cmdy:cmdy/fix-litellm-encrypted-content

Conversation

@cmdy

@cmdy cmdy commented Sep 20, 2026

Copy link
Copy Markdown

Summary

  • Recognize LiteLLM errors that wrap an OpenAI invalid_encrypted_content response inside error.message.
  • Reuse the existing single sanitized retry without changing existing OpenAI, ChatGPT, or xAI detection.
  • Reject unrelated LiteLLM 400 responses.

Verification

  • bun test tests/responses/responses-opaque-blob-recovery.test.ts
  • bun run typecheck
  • bun run structure:check
  • bun run privacy:scan

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

  • Bug Fixes

    • Improved recovery for LiteLLM-wrapped encrypted-content errors in Responses API requests.
    • Unrelated LiteLLM error responses continue without retrying.
  • Documentation

    • Documented handling of wrapped OpenAI errors during reactive recovery.
  • Tests

    • Added coverage for successful recovery, ignored unrelated errors, and sanitized resend behavior.

@github-actions github-actions Bot added the bug Something isn't working label Sep 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Deterministic PR hygiene checks passed.

@coderabbitai

coderabbitai Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: lidge-jun/opencodex/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Advanced

Run ID: a1b4c00f-9ea6-44aa-8e37-e0bf9c4c68c4

📥 Commits

Reviewing files that changed from the base of the PR and between 134c92a and 7e3e3c9.

📒 Files selected for processing (3)
  • src/server/responses/core-opaque-recovery.ts
  • structure/transports/responses.md
  • tests/responses/responses-opaque-blob-recovery.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

The change adds LiteLLM-wrapped OpenAI error detection to opaque-blob recovery. It parses bounded embedded JSON, preserves existing rejection checks, documents the behavior, and tests both recovery and non-recovery cases.

Changes

Opaque-blob recovery

Layer / File(s) Summary
Wrapped error payload matching
src/server/responses/core-opaque-recovery.ts
The matcher extracts bounded OpenAIException - {JSON} payloads from litellm.BadRequestError: messages. It applies the existing opaque-blob checks to the extracted payload.
Recovery behavior validation
tests/responses/responses-opaque-blob-recovery.test.ts
Tests cover matching LiteLLM errors, unrelated wrapped validation errors, and a sanitized retry that sends the request twice.
Recovery documentation
structure/transports/responses.md
The Responses transport documentation specifies the LiteLLM parsing boundary and required invalid_encrypted_content code.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Responses as /v1/responses
  participant Recovery as opaque-blob recovery
  participant LiteLLM
  Client->>Responses: send request containing opaque blob
  Responses->>LiteLLM: forward request
  LiteLLM-->>Responses: return wrapped OpenAI error
  Responses->>Recovery: inspect error payload
  Recovery-->>Responses: identify invalid_encrypted_content
  Responses->>LiteLLM: resend sanitized request without opaque blob
  LiteLLM-->>Responses: return success
  Responses-->>Client: return recovered response
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: recovery for LiteLLM-wrapped encrypted-content errors in Responses handling.
Full details: Docstring Coverage

Explanation

Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. (1 skipped: 1 unsupported.)

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions github-actions Bot changed the title fix(responses): recover LiteLLM-wrapped encrypted content errors [WRONG BRANCH] fix(responses): recover LiteLLM-wrapped encrypted content errors Sep 20, 2026
@github-actions

github-actions Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

⏳ DRAFT

  • review readiness checklist open (0/4 boxes ticked).

What to do

  • Tick all four boxes in the PR description once you're done (currently 0/4).

Review readiness checklist

  • ⬜ All CI tests are green on my local testing.
  • ⬜ I pushed my PR to the latest dev commit.
  • ⬜ I resolved all correct Codex and CodeRabbit findings.
  • ⬜ My PR is ready for review.

0/4 boxes ticked.

This PR stays in draft until every box above is ticked.

@github-actions
github-actions Bot marked this pull request as draft September 20, 2026 03:27
@lidge-jun

Copy link
Copy Markdown
Owner

리뷰 · 우선순위 66 / 80

이 PR은 LiteLLM이 OpenAI의 invalid_encrypted_content 거부를 바깥 error.message 글 안에 OpenAIException - {JSON} 형태로 감싸 돌려줄 때, opaque-blob 복구가 그 안쪽을 못 알아보던 구멍을 막습니다. 예전에는 OpenAI·ChatGPT·xAI가 직접 보내는 거부만 보고, LiteLLM이 감싼 400은 그냥 실패로 끝났습니다. 이번 수정은 core-opaque-recovery.tsliteLlmEmbeddedErrorPayload를 넣어 litellm.BadRequestError:로 시작하는 메시지에서 중괄호 깊이로 JSON만 잘라 파싱하고, 기존 판별 로직을 isOpaqueBlobErrorPayload로 빼서 안쪽 페이로드에 다시 돌립니다. 바깥 래퍼는 한 겹만 허용하고(allowLiteLlmWrapper → 재귀 때는 false), 안쪽이 opaque 거부가 아니면 재시도하지 않습니다. 재시도 자체는 예전과 같이 sanitized 요청 한 번뿐입니다. 테스트는 트리거 인정·관련 없는 LiteLLM 400 거절·/v1/responses에서 blob 제거 후 성공까지 세 축을 잡았고, structure/transports/responses.md에 한 문단을 보탰습니다. 범위는 복구 판별·문서·테스트 세 파일이고 types.ts/config.ts는 건드리지 않습니다. 같은 주제의 다른 열린 PR도 보이지 않습니다.

다만 베이스가 main입니다. 제목에 이미 [WRONG BRANCH]가 붙었고 enforce-target이 실패했으며, 초안·준비 체크 0/4입니다. 기여 레인은 dev이므로 코드가 좋아도 지금은 머지 후보가 아닙니다. hygiene·label·resolve-pr·CodeRabbit은 통과했습니다. 본문에 적힌 bun test/typecheck/structure:check/privacy:scan은 이 원격 머리에서 다시 돌리지 않았습니다.

라인 - src/server/responses/core-opaque-recovery.ts isOpaqueBlobErrorPayload LiteLLM 분기: 문서는 안쪽이 invalid_encrypted_content여야 한다고만 적지만, 코드는 재귀로 ChatGPT 검증 실패 문구·caller-mismatch·xAI compaction/decrypt 문구까지 모두 통과시킵니다. 동작은 넓은 쪽이 맞고, 문서만 좁습니다.
라인 - 같은 파일 liteLlmEmbeddedErrorPayload: 메시지가 정확히 litellm.BadRequestError:로 시작해야 합니다. 앞뒤 공백이나 다른 LiteLLM 예외 이름이면 안 잡힙니다. 지금은 안전한 보수이고, 실제 프로덕션 문자열과 맞는지 한 번만 확인하면 됩니다.
라인 - structure/transports/responses.md 추가 문단: “inner code invalid_encrypted_content”만 적혀 있어 위 코드와 어긋납니다. “안쪽 페이로드가 기존 opaque 거부 신원 중 하나”로 고치거나, 정말 그 코드만 허용하려면 재귀 판별을 좁혀야 합니다.
경로/baseRefName - 베이스가 main입니다. opencodex 기여는 dev로 들어와야 하고, 게이트가 Draft로 잠근 상태입니다.
경로/PR 본문 - 준비 체크리스트 0/4. 로컬 CI·최신 dev 반영·CodeRabbit 정리가 끝나기 전에는 Ready로 올리면 안 됩니다.

메인테이너의 판단이 필요한 지점

LiteLLM으로 감싼 ChatGPT/xAI/caller-mismatch 거부까지 같은 한 번 재시도를 허용할지(지금 코드), 아니면 문서대로 invalid_encrypted_content만 허용할지. 또 wrong-branch Draft를 dev로 리타깃해 이 PR을 살릴지, 같은 커밋을 dev 대상 새 PR로 다시 받을지.

너의 추천

베이스를 dev로 리타깃(또는 dev 대상 새 PR)한 뒤, 문서 문장을 코드의 “기존 opaque 신원 전부”에 맞추고 체크리스트를 채우세요. 그다음 exact-head에서 opaque-blob 복구 테스트와 typecheck가 초록이면 머지해도 됩니다. 판별 범위는 지금처럼 넓게 두는 편이 낫고, litellm.BadRequestError: 접두 고정은 유지하세요. types/config 분할로 닫을 PR이 아니고, 중복 닫기 대상도 아닙니다. 지금은 Draft를 유지하세요.

이 댓글은 grok-bot이 작성했습니다

@cmdy
cmdy force-pushed the cmdy/fix-litellm-encrypted-content branch from 7e3e3c9 to 59bf39b Compare September 20, 2026 06:18
@github-actions github-actions Bot added the intake: hygiene-blocked Deterministic PR hygiene checks failed label Sep 20, 2026
@cmdy cmdy changed the title [WRONG BRANCH] fix(responses): recover LiteLLM-wrapped encrypted content errors fix(responses): recover LiteLLM-wrapped encrypted content errors Sep 20, 2026
@cmdy
cmdy changed the base branch from main to dev September 20, 2026 06:19
@github-actions github-actions Bot removed the intake: hygiene-blocked Deterministic PR hygiene checks failed label Sep 20, 2026
@lidge-jun

Copy link
Copy Markdown
Owner

추가 리뷰 · 우선순위 73 / 80

이전 리뷰 이후 머리가 7e3e3c93에서 59bf39bd로 force-push 되었고, 베이스가 main에서 dev로 바뀌었으며 제목의 [WRONG BRANCH]도 빠졌습니다. dev 대비 ahead 1·behind 0이라 기여 레인 문제는 해소됐고 enforce-target도 통과합니다. 코드 쪽 핵심은 그대로입니다. LiteLLM이 error.messagelitellm.BadRequestError: … OpenAIException - {JSON}로 감싼 거부를 liteLlmEmbeddedErrorPayload로 잘라 파싱하고, isOpaqueBlobErrorPayload(..., allowLiteLlmWrapper)로 기존 opaque 신원에 한 겹만 재귀 적용한 뒤 sanitized 재시도 한 번으로 복구합니다. 관련 없는 LiteLLM 400은 그대로 거절합니다. 이번에 문서(structure/transports/responses.md)가 “inner code invalid_encrypted_content만”이 아니라 “기존에 인정하는 opaque 거부 신원 전부”로 고쳐져, 이전 리뷰에서 지적한 문서·코드 어긋남은 해소됐습니다. 범위는 여전히 복구 판별·문서·테스트 세 파일이고 types/config 분할·같은 주제 중복 PR은 없습니다. 다만 아직 Draft이고 준비 체크리스트는 0/4입니다. hygiene·label·resolve-pr·CodeRabbit은 최근 머리에서 통과 쪽으로 보이지만, 본문에 적힌 bun test/typecheck/structure:check/privacy:scan은 이 원격 머리에서 다시 돌리지 않았습니다.

라인 - structure/transports/responses.md LiteLLM 문단: 이전 지적(코드는 넓은 opaque 신원, 문서는 invalid_encrypted_content만)은 이번 push에서 맞춰졌습니다. 추가 수정은 필요 없습니다.
라인 - src/server/responses/core-opaque-recovery.ts liteLlmEmbeddedErrorPayload: 메시지가 정확히 litellm.BadRequestError:로 시작해야 합니다. 앞 공백·다른 예외 이름이면 안 잡힙니다. 안전한 보수이니 유지하되, 실제 프로덕션 문자열과 한 번만 맞는지 확인하면 됩니다.
라인 - tests/responses/responses-opaque-blob-recovery.test.ts: LiteLLM 커버는 OpenAI invalid_encrypted_content 감싼 경우·관련 없는 400·sanitized 재시도 성공입니다. 문서가 말하는 ChatGPT/xAI/caller-mismatch를 LiteLLM 래퍼로 감싼 케이스는 없습니다. 필수는 아니지만 한 케이스만 더 있으면 문서·코드·테스트가 같은 폭으로 맞습니다.
경로/PR 본문 - 준비 체크리스트 0/4, 상태 Draft. 로컬 CI·최신 dev 반영·CodeRabbit 정리·Ready 표시가 끝나기 전에는 머지 후보가 아닙니다.

메인테이너의 판단이 필요한 지점

LiteLLM으로 감싼 ChatGPT/xAI/caller-mismatch까지 같은 한 번 재시도를 허용하는 현재 코드(그리고 이제 문서)를 그대로 둘지. 테스트에 그 래퍼 조합을 추가할지는 품질 선택입니다.

너의 추천

베이스·문서 문제는 해결됐으니, 체크리스트를 채우고 exact-head에서 opaque-blob 복구 테스트와 typecheck가 초록이면 Ready로 올린 뒤 머지해도 됩니다. litellm.BadRequestError: 접두 고정은 유지하세요. LiteLLM+다른 opaque 신원 테스트 한 줄은 있으면 좋고 없어도 막지는 마세요. types/config 분할·중복 닫기 대상은 아닙니다.

이 댓글은 grok-bot이 작성했습니다

@lidge-jun

Copy link
Copy Markdown
Owner

Carried in narrowed form by #5266, merged to dev as 043aa435ff8f86095f55cbe08f74d45b9858da59, with attribution in the branch commit. Leaving this open rather than closing it, because the landed version deliberately admits less than this one does.

What landed: a gateway envelope is decided only by its embedded payload, and only an embedded invalid_request_error / invalid_encrypted_content is admitted through the wrapper.

Why not the full classifier: rerunning the whole opaque classifier on the embedded payload would also admit the code-less unverifiable-ciphertext wording, the #4469 caller mismatch, and the two decoder strings — identities that rest on evidence about how one specific upstream words its own rejection, which a gateway in between is not. The pre-existing anchored-wording checks already run on the whole message, and a gateway quotes the upstream's message inside its own, so a relayed caller mismatch would otherwise have satisfied the #4469 identity and gained exactly the resend that the strict check exists to withhold.

If you have evidence that a specific gateway's relayed wording is safe to treat as its own identity, that is the thing to add here.

@cmdy

cmdy commented Sep 20, 2026

Copy link
Copy Markdown
Author

Superseded by #5266, which includes the LiteLLM wrapped ciphertext recovery fix and preserves the contribution with a Co-authored-by trailer. Closing this duplicate PR.

@cmdy cmdy closed this Sep 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants