NOUKAI

Errors & Retries

Handle SDK exceptions with typed error codes and automatic retry logic.

The SDKs raise typed exceptions for different failure modes. Handle them by exception type or via the .code attribute.

Exception hierarchy

All SDK exceptions inherit from NoukaiError:

NoukaiError (base)
├── APIConnectionError       # Connection to Noukai failed
├── APITimeoutError          # Request timed out
├── AuthenticationError       # API key invalid or missing
├── PermissionDeniedError     # User lacks access to flow
├── FlowNotFoundError         # Flow not found
├── InsufficientCreditsError  # Account out of credits
├── RateLimitError            # Rate limit exceeded
├── FlowExecutionError        # Flow execution failed
└── ToolCallLimitError        # Tool calls exceeded limit

Catching exceptions

Catch by type:

from noukai_sdk import (
    Noukai,
    FlowNotFoundError,
    InsufficientCreditsError,
    NoukaiError
)
 
try:
    with Noukai(org="acme", project="spelling") as client:
        result = client.flow("grade-3").execute(message="hello")
except FlowNotFoundError:
    print("Flow not found — check the flow slug")
except InsufficientCreditsError:
    print("Account out of credits — top up account")
except NoukaiError as e:
    print(f"Noukai error: {e}")
except Exception as e:
    print(f"Other error: {e}")

Error codes

Each exception has a .code attribute for programmatic dispatch:

try:
    result = client.flow("...").execute(message="...")
except NoukaiError as e:
    if e.code == "flow_not_found":
        # Handle missing flow
        pass
    elif e.code == "insufficient_credits":
        # Handle billing
        pass
    elif e.code == "authentication_error":
        # Handle auth
        pass
    else:
        # Generic error handling
        raise

Code reference

ExceptionCodeHTTPMeaning
AuthenticationErrorauthentication_error401API key invalid/missing
PermissionDeniedErrorpermission_denied403User lacks access
FlowNotFoundErrorflow_not_found404Flow doesn't exist
InsufficientCreditsErrorinsufficient_credits402Account out of credits
RateLimitErrorrate_limit_exceeded429Rate limited
APITimeoutErrorapi_timeout504Request timed out
APIConnectionErrorapi_connectionConnection failed
FlowExecutionErrorflow_execution_error500Flow execution failed
ToolCallLimitErrortool_call_limitTool call limit exceeded

Automatic retries

The SDK automatically retries on transient errors (5xx, timeouts):

  • Retry condition: 5xx status code or timeout
  • Retry limit: 1 retry by default
  • Backoff: Exponential backoff with jitter (100ms → 200ms)
  • Non-retryable: 4xx errors (auth, not found, etc.) are not retried

Example: A request that times out is retried once. If it times out again, APITimeoutError is raised.

Controlling retries

The SDK uses a fixed retry policy (1 retry, exponential backoff). To customize:

from noukai_sdk import APITimeoutError
import time
 
def execute_with_retries(fn, max_retries=3, backoff_factor=2):
    for attempt in range(max_retries):
        try:
            return fn()
        except APITimeoutError as e:
            if attempt == max_retries - 1:
                raise
            wait_time = backoff_factor ** attempt
            print(f"Retrying in {wait_time}s...")
            time.sleep(wait_time)
 
result = execute_with_retries(
    lambda: client.flow("acme/spelling/grade-3").execute(message="hello"),
    max_retries=3
)

Error details

Exceptions include structured error details:

from noukai_sdk import FlowExecutionError
 
try:
    result = client.flow("...").execute(message="...")
except FlowExecutionError as e:
    print(f"Code: {e.code}")
    print(f"Message: {str(e)}")
    print(f"HTTP status: {e.status_code}")
    if hasattr(e, 'response'):
        print(f"Response: {e.response}")

Handling tool call errors

Tool calls can fail if the flow hits its retry limit:

from noukai_sdk import ToolCallLimitError
 
def my_tool_handler(tool_calls):
    results = []
    for tc in tool_calls:
        try:
            result = call_my_tool(tc)
        except Exception as e:
            # If tool fails, return error content
            results.append({
                "role": "tool",
                "tool_call_id": tc["id"],
                "content": f"Error: {e}"
            })
        else:
            results.append({
                "role": "tool",
                "tool_call_id": tc["id"],
                "content": result
            })
    return results
 
try:
    result = client.flow("...").execute(
        message="...",
        tools=[...],
        tool_handler=my_tool_handler
    )
except ToolCallLimitError:
    print("Tool calls failed after all retries")

Common errors and solutions

FlowNotFoundError

Solution: Verify the flow slug in Noukai Console.

try:
    result = client.flow("typo/flow/name").execute(message="...")
except FlowNotFoundError:
    print("Flow slug may be incorrect")
    print("Check: https://console.noukai.xyz/flows")

AuthenticationError

Solution: Check the API key is set correctly.

try:
    result = client.flow("...").execute(message="...")
except AuthenticationError:
    print("API key invalid or expired")
    print("Set: export NOUKAI_API_KEY=nk_...")

InsufficientCreditsError

Solution: Add credits to your account.

try:
    result = client.flow("...").execute(message="...")
except InsufficientCreditsError:
    print("Account out of credits")
    print("Top up at: https://console.noukai.xyz/billing")

RateLimitError

Solution: Implement exponential backoff or contact support.

try:
    result = client.flow("...").execute(message="...")
except RateLimitError:
    import time
    time.sleep(60)  # Back off and retry

APITimeoutError

Solution: Retry manually or check Noukai status page.

Logging errors

Enable logging to see detailed error information:

import logging
 
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger("noukai_sdk")
logger.setLevel(logging.DEBUG)
 
# Now SDK errors will be logged with full details

Next steps

On this page