Agent Skills: Oracle Cloud Common Errors

|

UncategorizedID: jeremylongshore/claude-code-plugins-plus-skills/oraclecloud-common-errors

Install this agent skill to your local

pnpm dlx add-skill https://github.com/jeremylongshore/claude-code-plugins-plus-skills/tree/HEAD/plugins/saas-packs/oraclecloud-pack/skills/oraclecloud-common-errors

Skill Files

Browse the full folder contents for oraclecloud-common-errors.

Download Skill

Loading file tree…

plugins/saas-packs/oraclecloud-pack/skills/oraclecloud-common-errors/SKILL.md

Skill Metadata

Name
oraclecloud-common-errors
Description
|

Oracle Cloud Common Errors

Overview

OCI API errors are notoriously cryptic. NotAuthorizedOrNotFound (404) could mean an IAM policy is missing or you typed the OCID wrong — the error is intentionally ambiguous for security. NotAuthenticated (401) covers six different config file problems. CERTIFICATE_VERIFY_FAILED has different fixes depending on your SDK language, OS, and whether you are behind a corporate proxy.

Purpose: A diagnostic decoder ring mapping every common OCI error to its real root cause and fix, with runnable diagnostic commands for each scenario.

Prerequisites

  • An OCI account with ~/.oci/config configured (see oraclecloud-install-auth)
  • Python 3.8+ with pip install oci installed
  • OCI CLI installed (pip install oci-cli) for diagnostic commands

Instructions

Authentication Errors (401 NotAuthenticated)

The 401 error has six distinct root causes. Run this diagnostic to isolate which one:

import oci
import os

def diagnose_auth():
    """Diagnose OCI 401 NotAuthenticated errors."""
    config_path = os.path.expanduser("~/.oci/config")

    # Check 1: Config file exists
    if not os.path.exists(config_path):
        return "CAUSE: Config file missing. Run: oci setup config"

    config = oci.config.from_file(config_path)

    # Check 2: All required fields present
    required = ["user", "fingerprint", "tenancy", "region", "key_file"]
    for field in required:
        if field not in config or not config[field]:
            return f"CAUSE: Missing field '{field}' in ~/.oci/config"

    # Check 3: Key file exists
    key_path = os.path.expanduser(config["key_file"])
    if not os.path.exists(key_path):
        return f"CAUSE: Key file not found: {key_path}"

    # Check 4: Key is private (not public)
    with open(key_path, "r") as f:
        first_line = f.readline().strip()
    if "PUBLIC" in first_line:
        return "CAUSE: key_file points to PUBLIC key. Use the private key (no _public suffix)"

    # Check 5: Key file permissions
    perms = oct(os.stat(key_path).st_mode)[-3:]
    if perms != "600":
        return f"CAUSE: Key permissions are {perms}. Run: chmod 600 {key_path}"

    # Check 6: Fingerprint matches
    return "Config looks valid. Fingerprint mismatch? Verify in Console > User Settings > API Keys"

print(diagnose_auth())

401 Root Cause Table:

| Symptom | Root Cause | Fix | |---------|-----------|-----| | did not find a proper configuration for user | Missing or malformed ~/.oci/config | Recreate with oci setup config | | could not find private key | key_file path wrong or file missing | Check path; key must exist at that location | | private key does not match | Fingerprint in config does not match uploaded public key | Upload correct public key or regenerate pair | | key_file points to public key | key_file=~/.oci/oci_api_key_public.pem | Change to key_file=~/.oci/oci_api_key.pem (private key) | | permission denied reading key | Key file permissions too open | chmod 600 ~/.oci/oci_api_key.pem | | InvalidKeyId | User OCID or tenancy OCID wrong | Verify OCIDs in Console > Profile > User Settings |

Authorization Errors (404 NotAuthorizedOrNotFound)

This is the most confusing OCI error. A 404 means either the resource does not exist or you lack IAM permission to see it. OCI hides the distinction intentionally.

Diagnostic steps:

# Step 1: Verify the OCID format is correct
echo "ocid1.instance.oc1.iad.aaaa..." | grep -P '^ocid1\.\w+\.oc1\.'

# Step 2: Verify you can list resources in the compartment
oci compute instance list --compartment-id <COMPARTMENT_OCID> --limit 1

# Step 3: Check IAM policies affecting your user
oci iam policy list --compartment-id <TENANCY_OCID> --all \
  --query "data[?contains(statements[0], 'instances')]"

Common IAM policy fixes:

# Allow a group to manage compute in a compartment
allow group Developers to manage instances in compartment MyCompartment

# Allow a group to read all resources (useful for debugging)
allow group Developers to read all-resources in tenancy

SSL Certificate Errors (CERTIFICATE_VERIFY_FAILED)

# Diagnostic: check which CA bundle Python uses
import ssl
print(ssl.get_default_verify_paths())

# Fix 1: Install/update certifi
# pip install --upgrade certifi

# Fix 2: Point to system CA bundle (Linux)
import os
os.environ["REQUESTS_CA_BUNDLE"] = "/etc/ssl/certs/ca-certificates.crt"

# Fix 3: Corporate proxy — add proxy CA to certifi bundle
# cat proxy-ca.pem >> $(python -c "import certifi; print(certifi.where())")

SSL Fix by Environment:

| Environment | Fix | |------------|-----| | Linux (system Python) | pip install --upgrade certifi | | macOS | brew install ca-certificates + update certifi | | Corporate proxy | Add proxy CA cert to certifi bundle | | Docker container | Copy CA bundle: COPY ca-bundle.crt /etc/ssl/certs/ | | Air-gapped | Set REQUESTS_CA_BUNDLE to local CA file |

Rate Limit Errors (429 TooManyRequests)

OCI does not send a Retry-After header. You must implement your own backoff:

import oci
import time
import random

def handle_rate_limit(fn, max_retries=5):
    """Handle OCI 429 errors. No Retry-After header — use jittered backoff."""
    for attempt in range(max_retries):
        try:
            return fn()
        except oci.exceptions.ServiceError as e:
            if e.status == 429:
                delay = (2 ** attempt) + random.uniform(0, 2)
                print(f"Rate limited. Waiting {delay:.1f}s (attempt {attempt + 1})")
                time.sleep(delay)
            else:
                raise
    raise RuntimeError("Rate limit retries exhausted")

# Or use the built-in strategy
compute = oci.core.ComputeClient(
    config, retry_strategy=oci.retry.DEFAULT_RETRY_STRATEGY
)

Timeout Errors (ServiceError status -1)

A ServiceError with status == -1 means the SDK timed out before the server responded:

import oci

config = oci.config.from_file("~/.oci/config")

# Default has NO connection timeout. Always set both:
compute = oci.core.ComputeClient(
    config,
    timeout=(10, 60)  # (connect_timeout, read_timeout)
)

# Object Storage uploads need longer read timeout
object_storage = oci.object_storage.ObjectStorageClient(
    config,
    timeout=(10, 600)  # 10 min for large uploads
)

Internal Server Errors (500 InternalError)

import oci

# Check OCI service health first
# https://ocistatus.oraclecloud.com

# 500 errors are transient — use retry strategy
compute = oci.core.ComputeClient(
    oci.config.from_file("~/.oci/config"),
    retry_strategy=oci.retry.DEFAULT_RETRY_STRATEGY  # Retries 500, 502, 503, 504
)

Output

After working through this diagnostic guide you will have:

  • Identified the exact root cause of your OCI error from the error code and message
  • A runnable diagnostic script for 401 auth errors that checks all six failure modes
  • IAM policy statements to resolve 404 authorization errors
  • Correct timeout and retry configuration for 429 and 500 errors
  • SSL certificate fixes for your specific environment

Error Handling

Complete OCI Error Reference Table:

| Error | Status | Exception | Root Cause | Fix | |-------|--------|-----------|-----------|-----| | NotAuthenticated | 401 | ServiceError | Wrong config, key, or fingerprint | Run diagnose_auth() above | | NotAuthorizedOrNotFound | 404 | ServiceError | Missing IAM policy OR wrong OCID | Check OCID format, then IAM policies | | TooManyRequests | 429 | ServiceError | Rate limit exceeded | Backoff with jitter (no Retry-After header) | | InternalError | 500 | ServiceError | OCI service error | Retry; check https://ocistatus.oraclecloud.com | | Timeout | -1 | ServiceError | No response in time | Set timeout=(connect, read) on client | | CERTIFICATE_VERIFY_FAILED | — | SSLError | CA bundle outdated or proxy | Update certifi or set REQUESTS_CA_BUNDLE | | InvalidParameter | 400 | ServiceError | Malformed request body | Check OCID format and required fields | | Out of host capacity | 500 | ServiceError | No hosts available (ARM shapes) | Retry loop; see oraclecloud-hello-world |

Examples

One-command connectivity test:

# Tests auth + network + SSL in one call
oci iam region list --output table 2>&1 || echo "FAILED — run oraclecloud-common-errors diagnostic"

Catch-all error handler for scripts:

import oci
import sys

config = oci.config.from_file("~/.oci/config")
compute = oci.core.ComputeClient(config)

try:
    compute.list_instances(compartment_id=config["tenancy"])
    print("OK")
except oci.exceptions.ServiceError as e:
    print(f"OCI Error: {e.status} {e.code}")
    print(f"Message: {e.message}")
    print(f"Request ID: {e.request_id}")  # Include this in support tickets
    if e.status == 401:
        print("ACTION: Check ~/.oci/config — see oraclecloud-install-auth")
    elif e.status == 404:
        print("ACTION: Verify OCID and IAM policies — see 404 section above")
    elif e.status == 429:
        print("ACTION: Rate limited — implement backoff")
    elif e.status == -1:
        print("ACTION: Timeout — increase client timeout values")
    sys.exit(1)
except oci.exceptions.ConfigFileNotFoundError:
    print("ACTION: ~/.oci/config not found. Run: oci setup config")
    sys.exit(1)

Resources

Next Steps

Once errors are resolved, see oraclecloud-sdk-patterns for retry and timeout patterns to prevent errors proactively, or oraclecloud-local-dev-loop for a productive development workflow with fast feedback.