Skip to content

fix(openai): forward project to Batches and Files API clients - #43430

Open
Rainmemery wants to merge 6 commits into
BerriAI:mainfrom
Rainmemery:fix/openai-batches-project
Open

Rainmemery wants to merge 6 commits into
BerriAI:mainfrom
Rainmemery:fix/openai-batches-project

Conversation

@Rainmemery

Copy link
Copy Markdown

Problem

OpenAI project scoping is currently dropped by the Batches and Files API paths. The OpenAI SDK client used by openai_batches_instance / openai_files_instance is constructed from api_key, api_base, organization, ... — but never project — so with a multi-project key, requests hit the wrong project and fail with:

Cannot find file file-XXX, or project proj_YYY does not have access to it

organization is resolved from optional_params / litellm.organization / OPENAI_ORGANIZATION and forwarded on every call; project (the OpenAI-Project header, the client-level project= kwarg, or OPENAI_PROJECT env) has no equivalent path, even though the OpenAI SDK supports a client-level project argument.

Changes

  • types (GenericLiteLLMParams): accept project alongside organization, so project=... reaches the provider params from litellm.create_batch / litellm.file_* calls, the router, and proxy bodies.
  • openai.py (OpenAIFilesAPI / OpenAIBatchesAPI): get_openai_client takes project and forwards it to OpenAI(**kwargs) / AsyncOpenAI(**kwargs); every sync entry method (create_batch, retrieve_batch, cancel_batch, list_batches, create_file, file_content, file_content_streaming, retrieve_file, delete_file, list_files) takes a project parameter. None values are skipped by the existing locals() passthrough, so no behavior change when project is unset.
  • batches/main.py + files/main.py: resolve project from optional_params.project or OPENAI_PROJECT (mirroring the organization / OPENAI_ORGANIZATION resolution) and pass it through; files-side goes via OpenAICredentials which now carries project.
  • proxy: /v1/batches and /v1/files accept project in the request body (flows through the generic params), and fall back to the OpenAI-Project request header when the body does not set one. Body value wins.

Testing

New unit tests (tests/batches_tests/test_openai_project_passthrough.py, 8 cases):

  • get_openai_credentials carries explicit project and falls back to OPENAI_PROJECT env
  • OpenAIBatchesAPI.create_batch / OpenAIFilesAPI.retrieve_file forward project to the OpenAI client constructor; when project/organization are None they are omitted entirely (no behavior change for existing users)
  • litellm.create_batch(project=...) resolves through GenericLiteLLMParams into the provider instance call
  • litellm.create_batch() with only OPENAI_PROJECT env set picks it up
  • files_main.file_retrieve(project=...) passes through
pytest tests/batches_tests/test_openai_project_passthrough.py -q
8 passed

Existing batches/files unit tests still pass (the remaining e2e failures in test_openai_batches_and_files.py require live OPENAI_API_KEY credentials and fail identically without this change).

Fixes #41803

@Rainmemery
Rainmemery requested a review from a team September 27, 2026 07:07
@codecov

codecov Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@greptile-apps

greptile-apps Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 3/5

[Medium risk] Adds OpenAI project parameter to batches and files APIs.

The PR is not ready to merge because proxy clients cannot reliably use the selected project throughout a file or batch lifecycle

Findings

  1. P1 Project header stops at creation ▶
  2. P1 File project form field ignored ▶
  3. P2 Provider logic outside adapters ▶
  4. P2 New fields lack ReadOnly ▶
  5. P2 Proxy behavior lacks regression coverage ▶
  6. P2 Project variable lacks Final ▶

Summary

The PR carries OpenAI project selection through batch and file credential resolution, SDK client construction, and two proxy create endpoints

  • Project selection works in the direct OpenAI batch and file paths inspected
  • Proxy project selection is incomplete across resource operations, and multipart uploads do not honor a project form field

Reviews (1) · Last reviewed commit: "fix(openai): forward project to Batches ..."

Comment on lines +761 to +762
if data.get("project") is None and request.headers.get("OpenAI-Project"):
data["project"] = request.headers.get("OpenAI-Project")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Project header stops at creation A client can create a file or batch with OpenAI-Project, but follow-up handlers ignore it. Without a configured project, retrieval can fail with not-found

Knowledge Base Used: Provider adapters and capabilities

Comment on lines +761 to +762
if data.get("project") is None and request.headers.get("OpenAI-Project"):
data["project"] = request.headers.get("OpenAI-Project")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 File project form field ignored Multipart uploads never copy the project form field into request data. The environment default is used instead, or the header wins over the form value

Comment on lines +761 to +762
if data.get("project") is None and request.headers.get("OpenAI-Project"):
data["project"] = request.headers.get("OpenAI-Project")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Provider logic outside adapters This handler and the batch handler interpret OpenAI-Project in proxy code. Repository guidance requires provider-specific behavior inside llms/; satisfy that requirement before merging

Rule Used: What: Avoid writing provider-specific code outside of the llms/ directory. Why: This practice ensures better maintainability and reduces complexity over time. Good: ```python # Handle provider-specific logic within llms/vertex_ai/transformation.py ... (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread litellm/types/llms/openai.py Outdated
file: Required[FileTypes]
purpose: Required[CREATE_FILE_REQUESTS_PURPOSE]
expires_after: FileExpiresAfter | None
project: str | None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 New fields lack ReadOnly Both new TypedDict project fields omit ReadOnly[...]. The repository requires that qualification for TypedDict fields; satisfy it before merging

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment on lines +40 to +42
with patch("litellm.llms.openai.openai.OpenAI") as mock_openai:
mock_openai.return_value.batches.create.return_value = batch_response
OpenAIBatchesAPI().create_batch(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Proxy behavior lacks regression coverage These tests inspect mocked constructor arguments but never exercise proxy header forwarding. Repository guidance requires functional regression tests; cover that behavior before merging

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread litellm/llms/openai/common_utils.py Outdated
or "https://api.openai.com/v1"
)
resolved_organization = organization or litellm.organization or os.getenv("OPENAI_ORGANIZATION", None) or None
resolved_project = project or os.getenv("OPENAI_PROJECT", None) or None

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Project variable lacks Final The new resolved_project local has no Final annotation. The repository coding guide requires one for new variables; satisfy it before merging

Suggested change
resolved_project = project or os.getenv("OPENAI_PROJECT", None) or None
resolved_project: Final = project or os.getenv("OPENAI_PROJECT", None) or None

Context Used: AGENTS.md (source)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Comment thread litellm/proxy/batches_endpoints/endpoints.py Outdated
@veria-ai

veria-ai Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

PR overview

All previously flagged issues have been addressed. No open security concerns remain on this pull request.

Security review

No open security issues remain on this pull request.

Fixed/addressed: 1 · PR risk: 0/10

@codspeed

codspeed Bot commented Sep 27, 2026 •

Copy link
Copy Markdown
Contributor

Merging this PR will not alter performance

✅ 31 untouched benchmarks


Comparing Rainmemery:fix/openai-batches-project (13cca7a) with main (096b20b)

Open in CodSpeed

OpenAI project scoping (OpenAI-Project / client project=) is currently
dropped by the Batches and Files API paths. First step of plumbing it
through: accept 'project' alongside 'organization' in the shared
provider-params type, mirroring how organization is declared.

Signed-off-by: rain <1504569896@qq.com>
OpenAI project scoping (OpenAI-Project header / client project=) was
dropped by the Batches and Files API paths: the OpenAI SDK client was
constructed without the project argument, so multi-project keys failed
with "Cannot find file file-XXX, or project proj_YYY does not have
access to it".

- GenericLiteLLMParams accepts project alongside organization
- OpenAIFilesAPI / OpenAIBatchesAPI get_openai_client forwards project
  to OpenAI(**kwargs); every sync method takes a project parameter
- batches/files main resolve project from optional_params or
  OPENAI_PROJECT and pass it through get_openai_credentials
- proxy /batches and /files accept project in the body and fall back to
  the OpenAI-Project header
- unit tests cover param/env resolution and client construction

Fixes BerriAI#41803
…icts

project is a litellm param, not part of the OpenAI request bodies: it is
absorbed by GenericLiteLLMParams from kwargs and forwarded to the client
constructor. Declaring it on CreateFileRequest / LiteLLMBatchCreateRequest
made files.create(**create_file_data) type-check against a key the OpenAI
SDK never accepts (+2 reportCallIssue over the repo budget).

Also regenerates the dashboard schema.d.ts for the LiteLLM_Params /
updateLiteLLMParams project field.
…cycle behind an opt-in

Address review: project now resolves once via apply_openai_project_to_data and applies to create/retrieve/list/cancel/get/delete for both batches and files, closing the gap where a file or batch created in a project could not be read back. create_file now accepts the project form field. Client-supplied project is gated by general_settings.forward_openai_project (default drop), mirroring forward_openai_org_id, so it can no longer override the deployment credential. Add resolved_project Final annotation and functional proxy regression tests.
…hema.d.ts

The create_file project form field changes the generated OpenAPI spec, so the dashboard's schema.d.ts must carry the matching optional project on the three Body_create_file_* components or the 'Verify schema.d.ts matches the proxy OpenAPI spec' job fails.
@Rainmemery
Rainmemery force-pushed the fix/openai-batches-project branch from 57d2be2 to 57fd857 Compare October 6, 2026 17:13
@Rainmemery

Copy link
Copy Markdown
Author

Heads-up: the red misc / Run tests check on this PR was caused by the stale interactions OpenAPI compliance tests (CreateModelInteractionParams / hardcoded /interactions/{id} assertions), which upstream repaired in #43958 — not by this PR's changes.

I've rebased the branch onto current main (which also picks up the tests/test_litellm → tests/unit move; the three touched test files followed their renamed paths cleanly). Local run of the four affected test files: 341 passed, 2 skipped; the only local failures were 4 managed_files ownership tests that fail identically on a pristine main checkout in this environment (older prisma client missing prisma.Json).

Fresh CI should come back green on the rebased head.

After rebasing onto main (which removed the LIT002 mutable-construction
rule in BerriAI#43971), the '# mutable-ok' annotation on this line suppressed
nothing and tripped the LIT013 stale-suppression gate. The copy is a
deliberate rebinding, so annotate it as one.
@Rainmemery

Copy link
Copy Markdown
Author

One follow-up on the lint check: the rebased head tripped the LIT013 stale-suppression gate — the # mutable-ok annotation on the private data copy in list_batches suppressed nothing after main removed the LIT002 mutable-construction rule (#43971). Fixed in 13cca7a by annotating the line as what it is (rebind-ok); the checker now reports no violations on the touched lines.

This branch has not been deployed

No deployments
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.

[Bug]: OpenAI Batches and Files API drop project / OpenAI-Project parameter, causing access errors on multi-project keys

1 participant