RAPI Exceptions

Exceptions for the REST API client module: credential resolution, endpoint configuration, and HTTP requests.

Exception hierarchy

RapiError (base)
├── CredentialError           # Credential resolution failed
├── EndpointNotFoundError     # Endpoint not in config
├── EndpointAmbiguousError    # Short reference matches multiple endpoints
├── RequestError              # HTTP request failed
├── ResponseTooLargeError     # Response exceeds max size
├── ConfirmationRequiredError # Dangerous endpoint called without confirmation
└── SafeguardMissingError     # Dangerous method without safeguard in config

Common failure modes

  • CredentialError is raised when credential resolution fails (missing environment variable, file not found, or SOPS decryption error).

  • EndpointNotFoundError surfaces when the requested endpoint reference doesn’t match any configured endpoint.

  • EndpointAmbiguousError indicates a short reference (e.g., "users") matches endpoints in multiple APIs.

  • RequestError wraps HTTP failures including timeouts and 5xx errors after retry exhaustion.

  • ResponseTooLargeError indicates the response body exceeds the configured max_response_size limit.

  • ConfirmationRequiredError is raised at runtime when calling a dangerous endpoint (DELETE, PUT) without the required confirm parameter.

  • SafeguardMissingError is raised at config load time when an endpoint uses a dangerous method but lacks a safeguard string.

Usage patterns

Handling credential errors

from kstlib.rapi import RapiClient
from kstlib.rapi.exceptions import CredentialError

try:
    client = RapiClient()
    response = client.call("secure_api.endpoint")
except CredentialError as e:
    logger.error(f"Credential resolution failed: {e}")
    logger.error(f"Credential name: {e.credential_name}")
    # Check environment variable or credential file

Handling endpoint resolution

from kstlib.rapi import RapiClient
from kstlib.rapi.exceptions import EndpointNotFoundError, EndpointAmbiguousError

client = RapiClient()

try:
    response = client.call("users")  # Short reference
except EndpointAmbiguousError as e:
    # Multiple APIs have "users" endpoint
    logger.warning(f"Ambiguous: {e.matching_apis}")
    # Use full reference instead
    response = client.call("github.users")
except EndpointNotFoundError as e:
    logger.error(f"Endpoint not found: {e.endpoint_ref}")
    logger.error(f"Searched APIs: {e.searched_apis}")

Request error handling

from kstlib.rapi import RapiClient
from kstlib.rapi.exceptions import RequestError

client = RapiClient()

try:
    response = client.call("httpbin.delay", 60)  # May timeout
except RequestError as e:
    logger.error(f"Request failed: {e}")
    if e.retryable:
        logger.info("Error is retryable, consider retry later")
    if e.status_code:
        logger.info(f"HTTP status: {e.status_code}")

Response size validation

from kstlib.rapi import RapiClient
from kstlib.rapi.exceptions import ResponseTooLargeError

client = RapiClient()

try:
    response = client.call("api.large_endpoint")
except ResponseTooLargeError as e:
    logger.warning(f"Response too large: {e.size} bytes")
    logger.warning(f"Max allowed: {e.max_size} bytes")
    # Consider pagination or streaming

Safeguard confirmation

from kstlib.rapi import RapiClient
from kstlib.rapi.exceptions import ConfirmationRequiredError

client = RapiClient()

try:
    # Dangerous endpoint without confirmation
    client.call("admin.delete-user", user_id="123")
except ConfirmationRequiredError as e:
    logger.warning(f"Confirmation required: {e.expected}")
    # Ask user for confirmation, then retry
    if user_confirms():
        client.call("admin.delete-user", user_id="123", confirm=e.expected)

Safe wrapper pattern

from kstlib.rapi import RapiClient
from kstlib.rapi.exceptions import RapiError

def safe_api_call(endpoint: str, *args, **kwargs) -> dict | None:
    """Make API call with comprehensive error handling."""
    client = RapiClient()
    try:
        response = client.call(endpoint, *args, **kwargs)
        if response.ok:
            return response.data
        logger.warning(f"API returned {response.status_code}")
        return None
    except RapiError as e:
        logger.error(f"API call failed: {e}")
        return None

API reference

Exceptions for the RAPI module.

This module defines the exception hierarchy for REST API operations.

exception kstlib.rapi.exceptions.ConfirmationRequiredError(endpoint_ref, *, expected, actual=None)[source]

Bases: RapiError

Raised when a dangerous endpoint requires confirmation.

This exception is raised at runtime when calling an endpoint that has a safeguard configured but the confirm parameter is missing or incorrect.

endpoint_ref

Full endpoint reference (api.endpoint).

expected

Expected confirmation string.

actual

Actual confirmation string provided (None if missing).

Examples

>>> raise ConfirmationRequiredError("api.delete", expected="DELETE X")
Traceback (most recent call last):
...
kstlib.rapi.exceptions.ConfirmationRequiredError: ... requires confirmation...
__init__(self, endpoint_ref: 'str', *, expected: 'str', actual: 'str | None' = None) 'None' -> None[source]

Initialize ConfirmationRequiredError.

Parameters:
  • endpoint_ref (str) – Full endpoint reference (api.endpoint).

  • expected (str) – Expected confirmation string.

  • actual (str | None) – Actual confirmation string provided (None if missing).

exception kstlib.rapi.exceptions.CredentialError(credential_name, reason)[source]

Bases: RapiError

Raised when credential resolution fails.

credential_name

Name of the credential that failed.

reason

Reason for the failure.

Examples

>>> raise CredentialError("github", "Environment variable not set")
Traceback (most recent call last):
...
kstlib.rapi.exceptions.CredentialError: Credential 'github' failed: Environment variable not set
__init__(self, credential_name: 'str', reason: 'str') 'None' -> None[source]

Initialize CredentialError.

Parameters:
  • credential_name (str) – Name of the credential that failed.

  • reason (str) – Reason for the failure.

exception kstlib.rapi.exceptions.EndpointAmbiguousError(endpoint_name, matching_apis)[source]

Bases: RapiError

Raised when an endpoint name matches multiple APIs.

endpoint_name

The ambiguous endpoint name.

matching_apis

List of API names containing this endpoint.

Examples

>>> raise EndpointAmbiguousError("get_data", ["api1", "api2"])
Traceback (most recent call last):
...
kstlib.rapi.exceptions.EndpointAmbiguousError: Endpoint 'get_data' is ambiguous, found in: api1, api2
__init__(self, endpoint_name: 'str', matching_apis: 'list[str]') 'None' -> None[source]

Initialize EndpointAmbiguousError.

Parameters:
  • endpoint_name (str) – The ambiguous endpoint name.

  • matching_apis (list[str]) – List of API names containing this endpoint.

exception kstlib.rapi.exceptions.EndpointCollisionError(endpoint_ref, source_files)[source]

Bases: RapiError

Raised when endpoints collide in strict mode.

This exception is raised at config load time when the same endpoint reference is defined in multiple files and strict mode is enabled.

endpoint_ref

Full endpoint reference (api.endpoint).

source_files

List of files defining this endpoint.

Examples

>>> raise EndpointCollisionError("api.create", ["a.rapi.yml", "b.rapi.yml"])
Traceback (most recent call last):
...
kstlib.rapi.exceptions.EndpointCollisionError: Endpoint 'api.create' defined in multiple files...
__init__(self, endpoint_ref: 'str', source_files: 'list[str]') 'None' -> None[source]

Initialize EndpointCollisionError.

Parameters:
  • endpoint_ref (str) – Full endpoint reference (api.endpoint).

  • source_files (list[str]) – List of files defining this endpoint.

exception kstlib.rapi.exceptions.EndpointNotFoundError(endpoint_ref, searched_apis=None)[source]

Bases: RapiError

Raised when an endpoint cannot be resolved.

endpoint_ref

The endpoint reference that was not found.

searched_apis

List of API names that were searched.

Examples

>>> raise EndpointNotFoundError("unknown.endpoint")
Traceback (most recent call last):
...
kstlib.rapi.exceptions.EndpointNotFoundError: Endpoint 'unknown.endpoint' not found
__init__(self, endpoint_ref: 'str', searched_apis: 'list[str] | None' = None) 'None' -> None[source]

Initialize EndpointNotFoundError.

Parameters:
  • endpoint_ref (str) – The endpoint reference that was not found.

  • searched_apis (list[str] | None) – List of API names that were searched.

exception kstlib.rapi.exceptions.EnvVarError(var_name, source=None)[source]

Bases: RapiError

Raised when environment variable substitution fails.

This exception is raised at config load time when a required environment variable is not set and no default value is provided.

var_name

Name of the missing environment variable.

source

Source file or context where the variable was referenced.

Examples

>>> raise EnvVarError("VIYA_HOST")
Traceback (most recent call last):
...
kstlib.rapi.exceptions.EnvVarError: Environment variable 'VIYA_HOST' is not set...
__init__(self, var_name: 'str', source: 'str | None' = None) 'None' -> None[source]

Initialize EnvVarError.

Parameters:
  • var_name (str) – Name of the missing environment variable.

  • source (str | None) – Source file or context where the variable was referenced.

exception kstlib.rapi.exceptions.MinifyRequiresRawError(message=None)[source]

Bases: RapiError

Raised when --minify (compact JSON) is requested without --raw.

Rich console rendering reformats output regardless of compact JSON flags, so --minify without --raw is silently ineffective. Surface the constraint at flag-validation time with a hint pointing to --raw --minify.

The kstlib CLI raises typer.BadParameter directly for native Typer error formatting. This exception is exported for callers that need to surface the same constraint programmatically (for example, future pipeline steps exposing equivalent minify and out semantics).

message

Human-readable error message containing the hint.

Examples

>>> error = MinifyRequiresRawError()
>>> "--raw --minify" in str(error)
True
>>> isinstance(error, RapiError)
True
DEFAULT_MESSAGE = '--minify requires --raw (Rich rendering ignores compact JSON formatting). Hint: use --raw --minify.'
__init__(self, message: 'str | None' = None) 'None' -> None[source]

Initialize MinifyRequiresRawError.

Parameters:

message (str | None) – Optional custom message. Defaults to the canonical hint pointing to --raw --minify.

exception kstlib.rapi.exceptions.RapiError(message, *, details=None)[source]

Bases: KstlibError

Base exception for all RAPI errors.

message

Human-readable error message.

details

Additional error context as key-value pairs.

Examples

>>> raise RapiError("Something went wrong", details={"endpoint": "test"})
Traceback (most recent call last):
...
kstlib.rapi.exceptions.RapiError: Something went wrong
__init__(self, message: 'str', *, details: 'dict[str, Any] | None' = None) 'None' -> None[source]

Initialize RapiError.

Parameters:
  • message (str) – Human-readable error message.

  • details (dict[str, Any] | None) – Additional error context.

exception kstlib.rapi.exceptions.RequestError(message, *, status_code=None, response_body=None, retryable=False)[source]

Bases: RapiError

Raised when an HTTP request fails.

status_code

HTTP status code (if available).

response_body

Response body (if available).

retryable

Whether the error is potentially retryable.

Examples

>>> raise RequestError("Server error", status_code=500, retryable=True)
Traceback (most recent call last):
...
kstlib.rapi.exceptions.RequestError: Server error
__init__(self, message: 'str', *, status_code: 'int | None' = None, response_body: 'str | None' = None, retryable: 'bool' = False) 'None' -> None[source]

Initialize RequestError.

Parameters:
  • message (str) – Human-readable error message.

  • status_code (int | None) – HTTP status code (if available).

  • response_body (str | None) – Response body (if available).

  • retryable (bool) – Whether the error is potentially retryable.

exception kstlib.rapi.exceptions.ResponseTooLargeError(response_size, max_size)[source]

Bases: RapiError

Raised when response exceeds max_response_size limit.

response_size

Actual response size in bytes.

max_size

Maximum allowed size in bytes.

Examples

>>> raise ResponseTooLargeError(15_000_000, 10_000_000)
Traceback (most recent call last):
...
kstlib.rapi.exceptions.ResponseTooLargeError: Response size 15000000 exceeds limit 10000000
__init__(self, response_size: 'int', max_size: 'int') 'None' -> None[source]

Initialize ResponseTooLargeError.

Parameters:
  • response_size (int) – Actual response size in bytes.

  • max_size (int) – Maximum allowed size in bytes.

exception kstlib.rapi.exceptions.SafeguardMissingError(endpoint_ref, method)[source]

Bases: RapiError

Raised when endpoint requires safeguard but none is configured.

This exception is raised at config load time when an endpoint uses a method that requires a safeguard (e.g., DELETE, PUT) but no safeguard string is provided in the endpoint configuration.

endpoint_ref

Full endpoint reference (api.endpoint).

method

HTTP method that requires the safeguard.

Examples

>>> raise SafeguardMissingError("api.delete", "DELETE")
Traceback (most recent call last):
...
kstlib.rapi.exceptions.SafeguardMissingError: ... requires a safeguard...
__init__(self, endpoint_ref: 'str', method: 'str') 'None' -> None[source]

Initialize SafeguardMissingError.

Parameters:
  • endpoint_ref (str) – Full endpoint reference (api.endpoint).

  • method (str) – HTTP method that requires the safeguard.

exception kstlib.rapi.exceptions.ServerNotFoundError(server_name, available=None)[source]

Bases: RapiError

Raised when a named server profile does not exist.

server_name

The server name that was not found.

available

List of available server names.

Examples

>>> raise ServerNotFoundError("staging", available=["source", "target"])
Traceback (most recent call last):
...
kstlib.rapi.exceptions.ServerNotFoundError: Server profile 'staging' not found...
__init__(self, server_name: 'str', available: 'list[str] | None' = None) 'None' -> None[source]

Initialize ServerNotFoundError.

Parameters:
  • server_name (str) – The server name that was not found.

  • available (list[str] | None) – List of available server names.