{"record":{"id":"78d9a90a389647dc","repo":"BerriAI/litellm","slug":"oci-key-must-be-a-string-containing-the-pem-privat","errorCode":null,"errorMessage":"oci_key must be a string containing the PEM private key content. Got type: {type(oci_key).__name__}","messagePattern":"oci_key must be a string containing the PEM private key content\\. Got type: (.+?)","errorType":"exception","errorClass":"OCIError","httpStatus":400,"severity":"error","filePath":"litellm/llms/oci/common_utils.py","lineNumber":307,"sourceCode":"    }\n\n    signed_header_names: Final = [\n        \"date\",\n        \"(request-target)\",\n        \"host\",\n        \"content-length\",\n        \"content-type\",\n        \"x-content-sha256\",\n    ]\n    signing_string: Final = build_signature_string(method, path, headers_to_sign, signed_header_names)\n\n    _require_cryptography()\n\n    # Resolve the private key — prefer inline PEM content over file path\n    oci_key_content: str | None = None\n    if oci_key:\n        if not isinstance(oci_key, str):\n            raise OCIError(\n                status_code=400,\n                message=(\n                    f\"oci_key must be a string containing the PEM private key content. \"\n                    f\"Got type: {type(oci_key).__name__}\"\n                ),\n            )\n        oci_key_content = oci_key.replace(\"\\\\n\", \"\\n\").replace(\"\\r\\n\", \"\\n\")\n\n    private_key: Final = (\n        load_private_key_from_str(oci_key_content)\n        if oci_key_content\n        else load_private_key_from_file(oci_key_file)\n        if oci_key_file\n        else None\n    )\n\n    if private_key is None:\n        raise OCIError(","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/oci/common_utils.py#L289-L325","documentation":"In the manual signing path, if oci_key is truthy it must be a str containing PEM content; any other type (bytes, dict, path-like, list) raises OCIError(400) naming the offending type. The check exists because serialized keys (e.g. read as bytes from a vault) would otherwise fail later with a confusing serialization error.","triggerScenarios":"Passing oci_key=b'-----BEGIN PRIVATE KEY-----...' (bytes from AWS Secrets Manager / Vault SDKs), an OCI config dict, or accidentally passing the key *file path* as oci_key instead of its contents.","commonSituations":"Secret managers returning bytes; JSON-encoded secrets passed as parsed dicts; confusing oci_key (inline PEM string) with oci_key_file (path) and passing a path to oci_key.","solutions":["Decode bytes to str: oci_key=key_bytes.decode('utf-8').","If the value is a path, use oci_key_file (or OCI_KEY_FILE) instead of oci_key.","If the secret is JSON-wrapped, extract the PEM field: json.loads(secret)['pem'].","Confirm the value starts with '-----BEGIN' and ends with '-----END ... KEY-----'."],"exampleFix":"# before\noptional_params[\"oci_key\"] = secret_manager.get(\"oci_key\")  # bytes → OCIError 400\n\n# after\nkey = secret_manager.get(\"oci_key\")\nif isinstance(key, bytes):\n    key = key.decode(\"utf-8\")\noptional_params[\"oci_key\"] = key","handlingStrategy":"type-guard","validationCode":"key = optional_params.get(\"oci_key\")\nif isinstance(key, bytes):\n    key = key.decode(\"utf-8\")\nassert key is None or (isinstance(key, str) and \"-----BEGIN\" in key), \"oci_key must be PEM string content\"","typeGuard":"from typing import Any\n\ndef is_pem_key_string(v: Any) -> bool:\n    return isinstance(v, str) and v.lstrip().startswith(\"-----BEGIN\")","tryCatchPattern":"from litellm.llms.oci.common_utils import OCIError\ntry:\n    litellm.completion(model=\"oci/...\", messages=m)\nexcept OCIError as e:\n    if e.status_code == 400 and \"oci_key must be a string\" in str(e):\n        optional_params[\"oci_key\"] = optional_params[\"oci_key\"].decode(\"utf-8\")\n    raise","preventionTips":["Decode secret-manager bytes to str before assigning oci_key.","Use oci_key_file for paths — never put a path into oci_key.","Unit-test the credential normalization step of your integration."],"tags":["oci","authentication","type-validation","secrets"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}