BerriAI/litellm · critical · OCIError
Private key is required for OCI authentication. Provide eith
Error message
Private key is required for OCI authentication. Provide either oci_key or oci_key_file.
What it means
After resolving the private key from oci_key or oci_key_file, sign_with_manual_credentials raises OCIError(400) if no key could be obtained. It differs from the 401 missing-credentials error: it specifically means the key sources were present-but-falsy (e.g. empty strings) or the caller reached this path with neither key field set.
Source
Thrown at litellm/llms/oci/common_utils.py:325
raise OCIError(
status_code=400,
message=(
f"oci_key must be a string containing the PEM private key content. "
f"Got type: {type(oci_key).__name__}"
),
)
oci_key_content = oci_key.replace("\\n", "\n").replace("\r\n", "\n")
private_key: Final = (
load_private_key_from_str(oci_key_content)
if oci_key_content
else load_private_key_from_file(oci_key_file)
if oci_key_file
else None
)
if private_key is None:
raise OCIError(
status_code=400,
message="Private key is required for OCI authentication. Provide either oci_key or oci_key_file.",
)
signature: Final = private_key.sign(
signing_string.encode("utf-8"),
padding.PKCS1v15(),
hashes.SHA256(),
)
signature_b64: Final = base64.b64encode(signature).decode()
key_id: Final = f"{oci_tenancy}/{oci_user}/{oci_fingerprint}"
authorization: Final = (
'Signature version="1",'
f'keyId="{key_id}",'
'algorithm="rsa-sha256",'
f'headers="{" ".join(signed_header_names)}",'
f'signature="{signature_b64}"'View on GitHub (pinned to 6c2dcb801b)
Solutions
- Provide the PEM content via oci_key/OCI_KEY or a valid path via oci_key_file/OCI_KEY_FILE.
- Use None-coalescing instead of empty defaults: os.environ.get('OCI_KEY') or os.environ.get('OCI_KEY_FILE').
- Fail fast at startup if neither key source is configured.
- Prefer OCI_KEY_FILE pointing at the same PEM used in ~/.oci/config to avoid duplication.
Example fix
# before
os.environ["OCI_KEY"] = os.environ.get("OCI_KEY", "") # '' passes truthiness of presence, then 400
# after
if not (os.environ.get("OCI_KEY") or os.environ.get("OCI_KEY_FILE")):
raise RuntimeError("Configure OCI_KEY or OCI_KEY_FILE") Defensive patterns
Strategy: validation
Validate before calling
import os
key = os.environ.get("OCI_KEY") or None
key_file = os.environ.get("OCI_KEY_FILE") or None
assert key or (key_file and os.path.isfile(key_file)), "Provide OCI_KEY or an existing OCI_KEY_FILE" Try / catch
from litellm.llms.oci.common_utils import OCIError
try:
litellm.completion(model="oci/...", messages=m)
except OCIError as e:
if e.status_code == 400 and "Private key is required" in str(e):
raise ConfigError("set OCI_KEY (PEM content) or OCI_KEY_FILE (path)") from e
raise Prevention
- Never default key env vars to empty strings; leave them unset and check for None.
- Fail fast at startup if neither key source is present.
- Mirror ~/.oci/config as the source of truth for key location.
When it happens
Trigger: oci_key='' or oci_key_file='' (empty strings from unset env vars), or calling the signing helper directly without any key argument while user/fingerprint/tenancy happen to be set.
Common situations: os.environ.get('OCI_KEY', '') producing '' when the var is unset; Helm values defaulting key to empty string; partial config where the user copied only some fields from ~/.oci/config.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- The provided private key is not an RSA key, which is require
- Missing required OCI credentials: oci_user, oci_fingerprint,
- 'api_key' is required in litellm_params for WXO agents
- workspace, repository, and access_token are required
- Authentication failed. Check your BitBucket access token and
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/122b717af7e810dc.
Report an issue: GitHub.