github ncecere/terraform-provider-litellm v2.2.0

5 hours ago

Upgrade Notes

  • The tested backend moves from LiteLLM 1.98.0 to exactly LiteLLM 1.104.0. The published provider source remains registry.terraform.io/ncecere/litellm; Terraform >= 1.1.0, OpenTofu >= 1.6.0, and Go >= 1.24.0 for provider development are unchanged, and only optional write-only attributes require Terraform or OpenTofu >= 1.11.0. Published examples continue to constrain the provider to >= 2.0.1, < 3.0.0. No provider attribute is removed or retyped, and existing HCL, state, IDs, and imports remain valid, except for the new plan-time rejections listed in the next item.
  • Provider changes that can require action on an existing configuration:
    • litellm_key: assigning or changing project_id on an existing key is now a plan-time error, because LiteLLM 1.104.0 rejects it; remove project_id to detach, or replace the key with terraform taint and apply (this issues a new key secret). soft_budget changes now reach LiteLLM, which writes them to the key's budget row; when budget_id points at a shared budget, a plan-time warning says so.
    • litellm_agent: removing a Terraform-managed secret litellm_params key (for example api_key) is now a plan-time error, because LiteLLM 1.104.0 keeps a stored secret when an update omits it. The check cannot see the proxy version at plan time, so it also applies to older proxies. Set it to "", or replace the agent with terraform taint and apply. The agent data sources report secret values as LiteLLM's REDACTED_BY_LITELM placeholder.
    • litellm_model: pricing keys in additional_model_info or additional_model_info_json now produce a plan-time warning (see below).
    • litellm_prompt: refresh now removes a prompt from state when LiteLLM's database-only version history confirms it is gone, instead of failing.
    • litellm_jwt_key_mapping: from LiteLLM 1.102.0, deleting the mapped key also deletes its mappings; the next refresh then removes the mapping from state.
  • LiteLLM 1.102 through 1.104 introduced backend behavior changes that affect Terraform-managed configuration independently of this provider release. Review them before upgrading the proxy:
    • Every organization endpoint, including reads, requires a LiteLLM Enterprise license. Unlicensed proxies return HTTP 403 for litellm_organization, litellm_organization_member, and the organization data sources.
    • An organization max_budget of 0 now means zero allowance instead of unlimited (LiteLLM 1.103.0), and a project max_budget of 0 blocks all spend. Omit the attribute for an unlimited budget.
    • stdio MCP servers are disabled unless the proxy process sets LITELLM_ENABLE_MCP_STDIO=true; creating or switching a litellm_mcp_server to stdio otherwise fails.
    • Team-admin (non proxy-admin) keys can no longer update teams or projects unless general_settings.team_admin_editable_team_fields allows it. Manage litellm_team and litellm_project with a proxy-admin or org-admin key.
    • Pricing in model_info is ignored from LiteLLM 1.102.0. litellm_model now warns at plan time about pricing keys in additional_model_info and additional_model_info_json; creating or changing such a key fails at apply on LiteLLM 1.102.0 and later. Prices already stored in model_info keep applying after the LiteLLM upgrade, but move them to the dedicated cost attributes or additional_litellm_params (see the litellm_model "Custom pricing" documentation) before changing them. Dedicated cost attributes are unaffected.
    • Deleting a model now removes its name from unified access groups when no other deployment serves it, and renaming a model rewrites the name in access groups and in key, team, organization, project, and user models allowlists. Add lifecycle { create_before_destroy = true } to models referenced by access groups so replacements keep the name served; the litellm_model documentation describes the effects.
    • litellm_unified_access_group.assigned_team_ids is now computed by LiteLLM: it includes every team whose own access_group_ids lists the group. Manage a team link from one side only; configuring the group's list without a self-linked team causes a perpetual diff. Unknown team IDs are rejected with HTTP 400.
    • When config.yaml declares a setting, runtime writes to that setting are refused, so manage router fallbacks either in the file or through litellm_fallback, not both.

Security

  • Deleted or regenerated keys are detected again on LiteLLM 1.104.0, which answers /key/info for them with an archived row instead of 404: litellm_key and litellm_key_block no longer report a deleted key as present (or blocked = true), and unified access group membership checks no longer accept a deleted key's stale group list.
  • litellm_jwt_key_mapping can map a key by key_hash, so neither the raw key nor Terraform >= 1.11 write-only support is needed for that path.
  • Absence is only inferred from exact LiteLLM signals: a prompt is treated as gone only on LiteLLM's own "No versions found" 404, and a key only on an explicit status = "deleted". Agent, MCP, and credential secrets are still never read back into state from responses or echoed in diagnostics; new diagnostics name keys, never values.

Added

  • litellm_jwt_key_mapping key_hash: Map a key by its SHA-256 management identifier (for example litellm_key.example.id) instead of the write-only raw key_wo, using LiteLLM 1.104.0's token field. The raw key never appears in configuration, and Terraform 1.11 write-only support is not required for this path. Changing the hash replaces the mapping; it conflicts with key_wo/key_wo_version.
  • tpd_limit (tokens per day): Add optional tpd_limit to litellm_key, litellm_team, litellm_budget, and litellm_project, and computed tpd_limit to the litellm_key, litellm_team, litellm_budget, and litellm_project data sources and the litellm_teams, litellm_budgets, and litellm_projects lists. LiteLLM 1.104.0 stores it with the entity's other rate limits and enforces it only for batch submissions, at key and team scope (a budget's limit reaches keys through budget_id); a project's value is stored but not enforced; removing it sends an explicit null that clears the limit. Existing state reads the new attribute as null, so no migration is needed.
  • litellm_jwt_key_mapping issuer scope: Add optional jwt_issuer to the resource and computed jwt_issuer to both data sources. LiteLLM 1.104.0 scopes mappings by issuer plus claim pair; changing a configured issuer replaces the mapping with the same key_wo safeguards as a claim change, an omitted issuer preserves the existing scope, and the global scope is null.

Changed

  • Release workflow: Download Go modules before the offline API contract check in the release and contract-update workflows. The check resolves imports with GOPROXY=off, so a cold module cache made the tag build fail before any artifact was produced.
  • Development and release API contract: Re-pin the reproducible LiteLLM API contract from v1.98.0 to v1.104.0 (79645770fedc7ec2627e6468d31062f20f82aecc). The exporter verifies v1.104.0's 35 lazy feature routers, excludes undocumented Starlette transport routes from OpenAPI comparison, and requires the now-public PATCH /v2/organization/{organization_id} route in generated OpenAPI. All provider HTTP operations resolve unchanged; the 105 new upstream operations are classified in the reviewed inventory.
  • Documentation and diagnostics: Schema descriptions, diagnostics, and resource/data-source documentation no longer describe LiteLLM behavior as "v1.98" when LiteLLM 1.104.0 behaves the same; text that differs between the two versions now names both. litellm_team_member_add diagnostic summaries drop the version (for example "Unrepairable Membership-Only State" instead of "Unrepairable v1.98 Membership-Only State"); automation that matched the old summary text should match the new text.
  • litellm_organization_member documentation: LiteLLM's organization member-add endpoint (1.98.0 and 1.104.0) returns HTTP 500 whenever user_email is sent and user_id does not name an existing user, so the documented email-only example could never succeed. The example now creates the user first, and the limitation note states the exact condition. Provider behavior is unchanged.
  • Acceptance harness: make testacc no longer stops at the key_write_only case with "SMOKE_PRIVATE_ROOT: unbound variable" when run outside the upgrade matrix with Terraform 1.11 or newer.

Fixed

  • Data sources and prompts on multi-worker LiteLLM 1.104.0: The litellm_key and litellm_team data sources failed with "expected an object of strings" because LiteLLM 1.104.0 stores per-model limits inside metadata as objects; those dedicated structured members are now omitted from the metadata map, and all string members are unchanged. litellm_prompt destroy no longer fails with "Prompt Delete Not Confirmed", and create no longer fails with "Prompt Already Exists", when another worker's in-memory registry still serves a just-deleted database prompt, and refresh now removes a prompt from state when LiteLLM's database-only version history confirms it is gone (previously every 400/404 retained state).
  • litellm_mcp_server stdio diagnostic: LiteLLM 1.104.0 rejects creating a stdio server, or switching one to stdio, with HTTP 422 unless the proxy sets LITELLM_ENABLE_MCP_STDIO=true. The provider reported only a generic rejection; it now reports stdio MCP Servers Disabled with the remediation. The response body, which echoes request secrets, is still never shown.
  • litellm_user and litellm_budget clears: Removing max_budget or budget_duration from a user, or any scalar limit from a budget (max_budget, soft_budget, budget_duration, max_parallel_requests, tpm_limit, rpm_limit), sent nothing, so LiteLLM kept the old value: the user kept it silently, and the budget apply failed with "Provider produced inconsistent result". Updates now send the explicit null that LiteLLM 1.104.0 persists, which also resets the budget reset time when the duration is cleared. User tpm_limit and rpm_limit still cannot be cleared because LiteLLM drops those nulls.
  • litellm_team metadata after clearing member defaults: Once a team's member-budget defaults were cleared, LiteLLM keeps the server-owned team_member_budget_id, and every later metadata, tag, guardrail, or per-model limit change failed with "Team Metadata Composition Failed". LiteLLM 1.101.0 and later merge that ID back into every metadata update themselves, so on a proxy whose team rows carry tpd_limit (LiteLLM 1.103.0 and later) the provider no longer requires member defaults in the same request. On older proxies, including 1.98.0, where such an update would sever the member-budget relation, the provider keeps refusing it before any request. It never sends the ID and still verifies it on read-back.
  • Organization and project license diagnostics on LiteLLM 1.102.0+: LiteLLM gates every organization endpoint, including reads, behind an Enterprise license and returns HTTP 403. litellm_organization, litellm_organization_member, litellm_project, and their data sources reported generic read, create, update, or delete failures; they now report LiteLLM Enterprise License Required with LITELLM_LICENSE guidance. The 403 is still never treated as absence, so state is unchanged. Organization and project max_budget descriptions now state that 0 means zero allowance, and the team and project documentation describes the new team-admin restrictions.
  • litellm_key project, soft budget, and router settings on LiteLLM 1.104.0: LiteLLM 1.104.0 now applies project_id and soft_budget on /key/update. Assigning or changing a key's project is rejected by LiteLLM, so the provider now fails that plan before any request; removing project_id sends the explicit null LiteLLM requires to detach, and read-back records the detach. soft_budget is sent only when it changes, with a plan-time warning when budget_id is set, because LiteLLM writes it to a possibly shared budget row. router_settings gains weights, optional_pre_call_checks, and the service_unavailable_error_retries, not_found_error_retries, and default_retries retry-policy fields; previously any key with these set outside Terraform failed every read.
  • litellm_model credential detach and multi-worker reads on LiteLLM 1.104.0: Removing litellm_credential_name sent an empty string, which LiteLLM 1.104.0 rejects with HTTP 400 before any write; the provider now retries that detach once with the explicit null LiteLLM 1.104.0 requires. LiteLLM 1.98.0, which ignores null here, still receives the empty string first. Post-update verification now waits, within its existing bound, for workers that still show a cleared value or briefly answer HTTP 400 while reloading the updated model, and model reads (resource refresh and the litellm_model data source) tolerate HTTP 400 for about 25 seconds while workers load a newly written model; retry waits honor cancellation. A persistent 400 is still an error and never removes the model from state.
  • litellm_agent secret parameters on LiteLLM 1.104.0: LiteLLM 1.104.0 returns every secret litellm_params value (for example api_key) as REDACTED_BY_LITELM to all callers, proxy admins included, and keeps a stored secret when a PATCH omits it. Creating or updating an agent with a secret parameter failed with "Agent Create Not Confirmed". The provider now recognizes the marker for values of any type, keeps the configured secret, verifies every other returned value, and rejects removing a Terraform-managed secret key at plan time (set it to "", or replace the agent with terraform taint and apply; -replace alone is not enough), because LiteLLM would silently keep it.
  • litellm_mcp_server OAuth scopes on LiteLLM 1.104.0: LiteLLM 1.104.0 returns credentials.scopes (a list) and credentials.upstream_token_header to full proxy admins. The provider required credentials to be a string map, so every create, read, import, and destroy of a server with oauth_scopes failed, and the litellm_mcp_server data source rejected any projection other than a lone upstream_resource. Both now accept LiteLLM's documented projection, the resource verifies oauth_scopes after create and scope changes when LiteLLM returns them, and a configured credentials.upstream_token_header is verified like upstream_resource.
  • Deleted keys on LiteLLM 1.104.0: LiteLLM 1.104.0 answers /key/info for a deleted or regenerated key with HTTP 200 and the archived row (status = "deleted") instead of 404. litellm_key and litellm_key_block therefore never noticed a key deleted outside Terraform (a block on a deleted key stayed in state, possibly still reporting blocked = true), the litellm_key data source read deleted keys, and unified access group membership verification could accept a deleted key's stale access groups. Every /key/info consumer now treats the archived row as absence, accepts LiteLLM 1.98's status-less rows, and fails closed on an unrecognized status.
  • litellm_model custom pricing in model_info: LiteLLM 1.102.0 and later silently drop pricing sent in model_info, so a price in additional_model_info or additional_model_info_json was not saved, spend fell back to the catalog price, and apply then failed with "Provider produced inconsistent result" and a tainted model. Both attributes now warn at plan time about LiteLLM's pricing fields, tiered *_above_<N>_tokens rates, and the generated key/pricing_overrides fields. The warning is not an error, so existing configurations, and LiteLLM 1.101 and earlier where these keys still work, are unaffected. Set prices with the dedicated cost attributes or additional_litellm_params; the model documentation describes the one-time migration for models whose prices were stored in model_info on LiteLLM 1.101 or earlier. A contract test derives the pricing field set from the pinned OpenAPI so a future LiteLLM pin cannot drift silently.
  • litellm_jwt_key_mapping on LiteLLM 1.104.0: Every create, read, import, and data-source read failed with "Invalid API Response" because LiteLLM 1.104.0 returns a new jwt_issuer field that the strict decoder rejected. Responses with and without the field are now accepted, and issuer identity is verified on every read-back. Deleting a mapping's virtual key now also deletes the mapping upstream; the resource documentation describes how to re-create both together.
  • litellm_agent / litellm_agents data sources: Agents with secret litellm_params (for example api_key) no longer fail the read with "Invalid API Response". LiteLLM 1.104.0 masks those values for every caller, proxy admins included, so the data sources now report LiteLLM's REDACTED_BY_LITELM placeholder, as the guardrail data source already does.
  • litellm_mcp_servers data source on LiteLLM 1.104.0: The list failed with "malformed MCP server list" whenever a server had OAuth scopes, because LiteLLM 1.104.0 now returns proxy admins the redacted credential projection (scopes and non-secret admin-config strings) in the list too. That projection is accepted and still not exposed; any other credential member continues to fail the read without echoing its content.

Don't miss a new terraform-provider-litellm release

NewReleases is sending notifications on new releases.