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

  1. Provide the PEM content via oci_key/OCI_KEY or a valid path via oci_key_file/OCI_KEY_FILE.
  2. Use None-coalescing instead of empty defaults: os.environ.get('OCI_KEY') or os.environ.get('OCI_KEY_FILE').
  3. Fail fast at startup if neither key source is configured.
  4. 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

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

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/122b717af7e810dc. Report an issue: GitHub.