> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiddenlayer.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting

> Diagnose and fix common problems with the HiddenLayer Python SDK, including installation, authentication, connection, and model scanning issues.

This page lists common problems with the HiddenLayer Python SDK, grouped by the symptom you see. Each entry explains the likely cause and how to fix it. If your problem is not listed, work through the [debug checklist](#debug-checklist) at the end of the page.

For background on the exception types mentioned here, see [Error handling](/docs/integrations/sdk_python/error_handling).

## Installation and setup

> **ModuleNotFoundError: No module named 'hiddenlayer'**
>
> **Cause:** The SDK is not installed in the Python environment that runs your code. This usually happens when you install the package in one virtual environment and run the script with a different Python interpreter.
>
> **Fix:**
>
> 1. Activate the virtual environment for your project.
> 2. Install the package with the same interpreter that runs your code:
>
> **macOS/Linux**
>
> ```bash theme={null}
> python -m pip install hiddenlayer-sdk
> python -c "import hiddenlayer; print(hiddenlayer.__version__)"
> ```
>
> **Windows**
>
> ```powershell theme={null}
> py -m pip install hiddenlayer-sdk
> py -c "import hiddenlayer; print(hiddenlayer.__version__)"
> ```
>
> The package name on PyPI is `hiddenlayer-sdk`, but the import name is `hiddenlayer`. Installing a package named `hiddenlayer` does not install this SDK. See [Installation](/docs/integrations/sdk_python/installation).

> **ImportError: Python package boto3 / huggingface\_hub / azure-identity / azure-storage-blob is not installed**
>
> **Cause:** Some model scanning helpers depend on third-party packages that are not installed with the SDK. They are not SDK extras, so you install them separately.
>
> | Helper | Package to install |
> | - | - |
> | `client.model_scanner.scan_s3_model` | `boto3` |
> | `client.model_scanner.scan_azure_blob_model` | `azure-identity` and `azure-storage-blob` |
> | `client.model_scanner.scan_huggingface_model` | `huggingface_hub` |
>
> **Fix:** Install the package named in the error message into the same environment as the SDK, for example:
>
> ```bash theme={null}
> python -m pip install boto3
> ```

> **The installed version is older than expected, or a method is missing**
>
> **Cause:** Your environment is still using an older version of the SDK. This happens when you upgrade in a different environment, when a requirements file pins an old version, or when an IDE uses a different interpreter.
>
> **Fix:**
>
> 1. Print the version your code actually uses:
>
>    ```python theme={null}
>    import hiddenlayer
>
>    print(hiddenlayer.__version__)
>    ```
>
> 2. Upgrade with the same interpreter: `python -m pip install --upgrade hiddenlayer-sdk`.
>
> 3. Check for pins such as `hiddenlayer-sdk==...` in `requirements.txt` or `pyproject.toml`.
>
> See [Version compatibility and upgrades](/docs/integrations/sdk_python/versioning).

## Configuration errors

> **ValueError: Ambiguous URL; The HIDDENLAYER\_BASE\_URL env var and the environment argument are given**
>
> **Cause:** You passed `environment=` to the client constructor while the `HIDDENLAYER_BASE_URL` environment variable is also set. The SDK cannot tell which one you want, so it refuses to guess.
>
> **Fix:** Choose one way to select the API endpoint:
>
> * Remove `HIDDENLAYER_BASE_URL` from your environment and keep `environment=`.
> * Remove `environment=` and keep `HIDDENLAYER_BASE_URL`.
> * Keep both and pass `base_url=None` explicitly, which tells the SDK to use `environment`.
>
> **macOS/Linux**
>
> ```bash theme={null}
> unset HIDDENLAYER_BASE_URL
> ```
>
> **Windows**
>
> ```powershell theme={null}
> Remove-Item Env:HIDDENLAYER_BASE_URL
> ```

> **ValueError: Unknown environment: ...**
>
> **Cause:** The `environment` argument has a value the SDK does not recognize.
>
> **Fix:** Use one of the supported values:
>
> | Environment | Base URL |
> | - | - |
> | `prod-us` (default) | `https://api.us.hiddenlayer.ai` |
> | `prod-eu` | `https://api.eu.hiddenlayer.ai` |
>
> To connect to any other endpoint, such as a self-hosted container, use `base_url` instead of `environment`.

## Authentication and permission errors

> **401 AuthenticationError**
>
> **Cause:** The API did not accept your credentials. Common reasons:
>
> * **Missing environment variables.** The client constructs successfully without credentials. The error only appears when it sends a request without an `Authorization` header.
> * **Expired or deleted API key.** API keys have an expiration set when they are created. Expired keys are removed from the Console.
> * **Credentials for the wrong region.** An API key created in the US Console does not work against the EU API, and the reverse. The SDK requests its access token from the base URL you configured, so the credentials must belong to that region.
> * **Token request failed.** If the SDK cannot exchange the client ID and client secret for an access token, it sends the request without a token, and the API returns 401.
> * **Bearer token expired.** If you use `HIDDENLAYER_TOKEN`, the SDK does not refresh the token for you.
> * **Typos or extra whitespace** in the client ID or client secret.
>
> **Fix:**
>
> 1. Run the [environment variable check](#check-environment-variables) to confirm that the variables are set in the process that runs your code.
> 2. In the Console, confirm that the API key exists and has not expired. If needed, [create a new API key](/docs/products/console/apikey_aisec_platform#create-api-key).
> 3. Confirm that the client's environment (`prod-us` or `prod-eu`) matches the region where you created the key.
> 4. If you use a bearer token, get a new one, or switch to a client ID and client secret so the SDK refreshes tokens automatically.
> 5. Configure only one authentication method. If both are set, the client ID and client secret take precedence.
>
> See [Authentication and configuration](/docs/integrations/sdk_python/authentication).

> **403 PermissionDeniedError**
>
> **Cause:** Your credentials are valid, but the API key does not have permission for the operation you called. For example, a key that can run model scans might not be allowed to delete models.
>
> **Fix:** In the Console, edit the API key or create a new one with the permissions the operation needs. See [API permissions related to products or features](/docs/products/console/apikey_aisec_platform#api-permission-related-to-products-or-features). Grant only the permissions your workload needs.

> **404 NotFoundError**
>
> **Cause:** The API could not find the resource. Common reasons:
>
> * The ID is wrong. Check for typos, and check that you passed the right kind of ID, for example a scan ID rather than a model ID.
> * The resource exists in a different region. Resources created in `prod-us` are not visible from `prod-eu`.
> * The resource is not available yet. For example, scan results can take a moment to appear after you start a scan. With `wait_for_results=False`, the scanning helpers make up to 5 attempts when they receive a 404 before raising `NotFoundError`.
>
> **Fix:** Check the ID and the client's environment. If the resource was just created, wait briefly and try again, or use `wait_for_results=True`.

## Connection and rate limit errors

> **APIConnectionError: Connection error.**
>
> **Cause:** The SDK could not reach the API, even after its automatic retries. Common reasons:
>
> * No network access, or a DNS failure
> * A corporate proxy or firewall is blocking outbound HTTPS traffic
> * A typo in `base_url` or `HIDDENLAYER_BASE_URL`
> * A local AI Runtime Security container is not running or is listening on a different port
>
> **Fix:**
>
> 1. Print the underlying error, which explains the specific failure:
>
>    ```python theme={null}
>    import hiddenlayer
>    from hiddenlayer import HiddenLayer
>
>    client = HiddenLayer()
>    print("Base URL:", client.base_url)
>
>    try:
>        client.interactions.analyze(
>            metadata={"model": "test-model", "requester_id": "connectivity-check"},
>            input={"messages": [{"role": "user", "content": "Hello"}]},
>        )
>    except hiddenlayer.APIConnectionError as e:
>        print("Connection failed:", repr(e.__cause__))
>    except hiddenlayer.APIStatusError as e:
>        print("Connected. The API returned status", e.status_code)
>    else:
>        print("Connected successfully.")
>    ```
>
> 2. Check that the printed base URL is correct.
>
> 3. If you are behind a proxy, configure it on a custom HTTP client. See [Security and production guidance](/docs/integrations/sdk_python/security#tls-and-network-configuration).
>
> 4. If you use a local container, confirm that it is running and that `base_url` uses the correct host and port.

> **APITimeoutError: Request timed out.**
>
> **Cause:** A request took longer than the timeout. The default is 60 seconds, with 5 seconds to connect. Large payloads, slow networks, or temporary API load can cause this. The SDK retries timeouts before raising the error.
>
> **Fix:** Increase the timeout for the client or for a single request:
>
> ```python theme={null}
> from hiddenlayer import HiddenLayer
>
> client = HiddenLayer(timeout=120.0)
> ```
>
> See [Error handling](/docs/integrations/sdk_python/error_handling#timeouts).

> **429 RateLimitError**
>
> **Cause:** You are sending more requests than the API allows. The SDK retries 429 responses automatically, honoring any `retry-after` header, and raises `RateLimitError` only after all retries fail.
>
> **Fix:**
>
> * Reduce request concurrency or volume.
> * Increase `max_retries` so the SDK waits longer before giving up.
> * Avoid adding your own retry loop on top of the SDK's retries, which can make rate limiting worse.

## Model scanning issues

> **RuntimeError: Couldn't download model ...**
>
> **Cause:** `scan_s3_model` or `scan_azure_blob_model` could not download the model before scanning it. Common reasons are a wrong bucket, key, container, or blob name, missing cloud credentials, or no write access to the local download directory.
>
> **Fix:**
>
> 1. Print `e.__cause__` to see the original error from `boto3` or the Azure SDK.
> 2. Confirm that the object exists and that your AWS or Azure credentials can read it. `scan_s3_model` uses the standard AWS credential chain by default. `scan_azure_blob_model` uses `DefaultAzureCredential` by default.
> 3. Confirm that the process can write to `/tmp`.

> **A scan seems to hang**
>
> **Cause:** With `wait_for_results=True` (the default), the scanning helpers poll until the scan reaches `done`, `failed`, or `canceled`. There is no overall time limit, so a slow or stuck scan blocks your program. The `timeout` client setting applies only to individual HTTP requests.
>
> **Fix:**
>
> * For large models or CI pipelines, call the helper with `wait_for_results=False`. Then check the scan later with `client.model_scanner.scan_result(scan_id=...)`.
> * To enforce your own limit, run the scan in a worker thread or process and stop waiting after a deadline.
>
> See [Model scanning](/docs/integrations/sdk_python/model_scanning).

> **The scan status is failed**
>
> **Cause:** The scan finished, but the scanner could not process one or more files. The helpers return a `ScanReport` with `status == "failed"` instead of raising an exception.
>
> **Fix:** Inspect the report to find which files failed and why:
>
> ```python theme={null}
> import sys
>
> import hiddenlayer
> from hiddenlayer import HiddenLayer
>
> scan_id = sys.argv[1]
>
> with HiddenLayer() as client:
>     try:
>         report = client.model_scanner.scan_result(scan_id=scan_id)
>     except hiddenlayer.APIError as e:
>         sys.exit(f"Could not retrieve the scan: {e}")
>
> print("Status:", report.status)
> print("Files that failed to scan:", report.summary.files_failed_to_scan)
>
> for file_result in report.file_results or []:
>     if file_result.file_error:
>         # file_error is a list of error messages for this file.
>         print(file_result.file_location, "->", "; ".join(file_result.file_error))
> ```
>
> Unsupported or corrupted files are a common cause. If the errors are not clear, contact support with the scan ID.

> **Windows: errors writing to /tmp**
>
> **Cause:** `scan_s3_model` and `scan_azure_blob_model` always download to `/tmp`, and `scan_huggingface_model` uses `/tmp` by default. This path may not exist on Windows.
>
> **Fix:** For Hugging Face models, pass a Windows path with `local_dir=`. For S3 and Azure, download the file yourself and call `client.model_scanner.scan_file()`, or run the scan from WSL or a Linux container.
>
> > [!NOTE]
> >
> > Behavior of the `/tmp` paths on Windows has not been verified and needs confirmation.

## Warnings in your output

> **BetaWarning: \[BETA] ... This endpoint is not GA or Production ready**
>
> **Cause:** You called a beta endpoint, such as `client.runtime.evaluate_interaction` or a red team method. The warning is informational. Your request still succeeded.
>
> **Fix:** Review what beta status means in [Version compatibility and upgrades](/docs/integrations/sdk_python/versioning#beta-apis). If you accept the risk, hide the warning:
>
> ```python theme={null}
> import warnings
>
> import hiddenlayer
>
> warnings.filterwarnings("ignore", category=hiddenlayer.BetaWarning)
> ```

> **DeprecationWarning when calling client.models.cards.list**
>
> **Cause:** `client.models.cards.list()` is deprecated in favor of the `GET /asset-inventory/v2/assets` API endpoint. Python can show a `DeprecationWarning` when you call it.
>
> **Fix:** The method still exists in version 3.10.0, but avoid building new code on it. The replacement asset inventory endpoint is not exposed as a method in this SDK version.
>
> > [!NOTE]
> >
> > When a replacement SDK method will be available needs confirmation.

## Debug checklist

If your problem is not listed above, work through these steps. They collect the information support needs.

### Check the SDK version

```python theme={null}
import hiddenlayer

print(hiddenlayer.__version__)
```

Compare it with the latest release on [PyPI](https://pypi.org/project/hiddenlayer-sdk/).

### Check environment variables

This script reports whether each variable the SDK reads is set, without printing secret values:

```python theme={null}
import os

VARIABLES = [
    "HIDDENLAYER_CLIENT_ID",
    "HIDDENLAYER_CLIENT_SECRET",
    "HIDDENLAYER_TOKEN",
    "HIDDENLAYER_BASE_URL",
    "HIDDENLAYER_CUSTOM_HEADERS",
    "HIDDENLAYER_LOG",
]

for name in VARIABLES:
    value = os.environ.get(name)
    if value is None:
        status = "not set"
    elif value.strip() == "":
        status = "set but empty"
    elif value != value.strip():
        status = "set (has leading or trailing whitespace)"
    else:
        status = "set"
    print(f"{name}: {status}")
```

You need either both `HIDDENLAYER_CLIENT_ID` and `HIDDENLAYER_CLIENT_SECRET`, or `HIDDENLAYER_TOKEN`. If you set `HIDDENLAYER_BASE_URL`, do not also pass `environment=` to the client.

### Turn on debug logging

Set `HIDDENLAYER_LOG` to `debug` to log each request, retry, and response. Use `info` for less detail.

**macOS/Linux**

```bash theme={null}
export HIDDENLAYER_LOG=debug
python your_script.py
```

**Windows**

```powershell theme={null}
$env:HIDDENLAYER_LOG = "debug"
python your_script.py
```

> [!WARNING]
>
> Debug logs include request bodies, which can contain prompts, model outputs, and other sensitive data. Use debug logging only while troubleshooting, do not share the logs publicly, and never enable it in production. Review logs before you send them to anyone.

### Inspect raw response headers

Response headers can explain what happened, for example whether a request was blocked or rate limited. Use `with_raw_response` to access them:

```python theme={null}
import hiddenlayer
from hiddenlayer import HiddenLayer

with HiddenLayer() as client:
    try:
        raw = client.interactions.with_raw_response.analyze(
            metadata={"model": "test-model", "requester_id": "debug-check"},
            input={"messages": [{"role": "user", "content": "Hello"}]},
        )
    except hiddenlayer.APIStatusError as e:
        print("Status:", e.status_code)
        print("Headers:", dict(e.response.headers))
        print("Body:", e.body)
    else:
        print("Status:", raw.status_code)
        print("Headers:", dict(raw.headers))
        response = raw.parse()
        print("Evaluation:", response.evaluation)
```

### Contact support

If you still need help, contact HiddenLayer through the [Support Portal](/docs/resources/support/support_portal). Include:

* The SDK version and Python version
* The environment (`prod-us` or `prod-eu`) or base URL
* The full exception type and message
* Relevant IDs, such as a scan ID or workflow ID
* Debug logs with secrets and sensitive data removed

Never send your client secret or bearer token to support.
