Cobbl

Error Handling

Handle errors gracefully with the Cobbl SDK

The SDK throws CobblError for all error cases. This provides a consistent way to handle errors across your application.

CobblError

All SDK errors are instances of CobblError:

import { CobblError } from '@cobbl-ai/sdk'

try {
  const result = await adminClient.runPrompt('my-prompt', { topic: 'test' })
} catch (error) {
  if (error instanceof CobblError) {
    console.error(`Error [${error.code}]: ${error.message}`)
  }
}

Error Properties

PropertyTypeDescription
messagestringHuman-readable error message
codeCobblErrorCodeMachine-readable error code
detailsunknownAdditional error details (optional)

Utility Methods

isCobblError

Static method to check if an error is a CobblError:

import { CobblError } from '@cobbl-ai/sdk'

try {
  await adminClient.runPrompt('my-prompt', {})
} catch (error) {
  if (CobblError.isCobblError(error)) {
    // TypeScript knows error is CobblError here
    console.error(`Error code: ${error.code}`)
  }
}

toJSON

Convert the error to a JSON-serializable object for logging or transmission:

try {
  await adminClient.runPrompt('my-prompt', {})
} catch (error) {
  if (error instanceof CobblError) {
    // Serialize for structured logging
    console.error(JSON.stringify(error.toJSON()))
    // => { "name": "CobblError", "message": "...", "code": "NOT_FOUND", "details": {...} }
  }
}

Error Codes

CodeDescription
INVALID_CONFIGInvalid SDK configuration
INVALID_REQUESTMalformed request (missing required fields)
UNAUTHORIZEDInvalid or missing API key
FORBIDDENPrompt is disabled or access is forbidden
NOT_FOUNDResource not found (prompt doesn't exist)
ARCHIVEDPrompt has been archived
RATE_LIMIT_EXCEEDEDToo many requests
SERVER_ERRORServer-side error
NETWORK_ERRORNetwork connectivity issue
API_ERROROther API errors

Handling Specific Errors

With CobblAdminClient

import { CobblAdminClient, CobblError } from '@cobbl-ai/sdk'

try {
  const result = await adminClient.runPrompt('my-prompt', { topic: 'test' })
} catch (error) {
  if (error instanceof CobblError) {
    switch (error.code) {
      case 'UNAUTHORIZED':
        console.error('Invalid API key - check your configuration')
        break

      case 'FORBIDDEN':
        console.error('Prompt is disabled - enable it in the dashboard')
        break

      case 'NOT_FOUND':
        console.error('Prompt not found - verify the prompt slug')
        break

      case 'ARCHIVED':
        console.error('Prompt has been archived - restore it or use another')
        break

      case 'INVALID_REQUEST':
        console.error('Invalid request:', error.details)
        break

      case 'RATE_LIMIT_EXCEEDED':
        console.error('Rate limit exceeded - try again later')
        // Implement retry with backoff
        break

      case 'NETWORK_ERROR':
        console.error('Network error - check your connection')
        break

      case 'SERVER_ERROR':
        console.error('Server error - please try again')
        break

      default:
        console.error('Unexpected error:', error.message)
    }
  } else {
    console.error('Unknown error:', error)
  }
}

With CobblPublicClient

import { CobblPublicClient, CobblError } from '@cobbl-ai/sdk'

try {
  await publicClient.createFeedback({
    runId: 'run_abc123',
    helpful: 'helpful',
  })
} catch (error) {
  if (error instanceof CobblError) {
    switch (error.code) {
      case 'NOT_FOUND':
        console.error('Run ID not found - it may have expired')
        break

      case 'INVALID_REQUEST':
        console.error('Invalid feedback data:', error.details)
        break

      default:
        console.error('Failed to submit feedback:', error.message)
    }
  }
}

Graceful Fallbacks

Always provide fallback behavior for critical paths:

const generateGreeting = async (userName: string): Promise<string> => {
  try {
    const result = await adminClient.runPrompt('greeting', { name: userName })
    return result.output
  } catch (error) {
    // Log for debugging
    console.error('Failed to generate greeting:', error)

    // Return fallback content
    return `Hello, ${userName}! Welcome to our platform.`
  }
}

Retry Logic

For transient errors, implement retry with exponential backoff:

const runPromptWithRetry = async (
  slug: string,
  input: Record<string, string>,
  maxRetries = 3
) => {
  let lastError: Error | undefined

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await adminClient.runPrompt(slug, input)
    } catch (error) {
      if (error instanceof CobblError) {
        // Don't retry client errors
        if (['UNAUTHORIZED', 'FORBIDDEN', 'NOT_FOUND', 'ARCHIVED', 'INVALID_REQUEST'].includes(error.code)) {
          throw error
        }

        // Retry server/network errors
        lastError = error
        const delay = Math.pow(2, attempt) * 1000 // 1s, 2s, 4s
        await new Promise(resolve => setTimeout(resolve, delay))
      } else {
        throw error
      }
    }
  }

  throw lastError
}

Framework Examples

Express.js Error Middleware

import { CobblError } from '@cobbl-ai/sdk'

const errorHandler = (
  error: Error,
  req: express.Request,
  res: express.Response,
  next: express.NextFunction
) => {
  if (error instanceof CobblError) {
    switch (error.code) {
      case 'UNAUTHORIZED':
      case 'FORBIDDEN':
        return res.status(403).json({ error: 'Access denied' })

      case 'NOT_FOUND':
        return res.status(404).json({ error: 'Resource not found' })

      case 'RATE_LIMIT_EXCEEDED':
        return res.status(429).json({ error: 'Too many requests' })

      default:
        return res.status(500).json({ error: 'Internal server error' })
    }
  }

  return res.status(500).json({ error: 'An unexpected error occurred' })
}

app.use(errorHandler)

Next.js API Route

app/api/generate/route.ts
import { CobblAdminClient, CobblError } from '@cobbl-ai/sdk'
import { NextResponse } from 'next/server'

const adminClient = new CobblAdminClient({
  apiKey: process.env.COBBL_API_KEY!,
})

export const POST = async (request: Request) => {
  try {
    const body = await request.json()
    const result = await adminClient.runPrompt('generator', body)
    return NextResponse.json(result)
  } catch (error) {
    if (error instanceof CobblError) {
      const status = {
        UNAUTHORIZED: 401,
        FORBIDDEN: 403,
        NOT_FOUND: 404,
        RATE_LIMIT_EXCEEDED: 429,
      }[error.code] ?? 500

      return NextResponse.json(
        { error: error.message, code: error.code },
        { status }
      )
    }

    return NextResponse.json(
      { error: 'An unexpected error occurred' },
      { status: 500 }
    )
  }
}

Logging Best Practices

Log errors with context for debugging:

import { CobblError } from '@cobbl-ai/sdk'

try {
  const result = await adminClient.runPrompt(slug, input)
} catch (error) {
  if (error instanceof CobblError) {
    console.error({
      message: 'Prompt execution failed',
      code: error.code,
      errorMessage: error.message,
      details: error.details,
      promptSlug: slug,
      // Don't log sensitive input values in production
    })
  }
  throw error
}

Next Steps

On this page