Skip to content

Error Handling

The SDK provides typed exceptions for different error scenarios.

Exception Hierarchy

NovelAIError (base)
├── MissingAPIKeyError
├── AuthenticationError
├── InvalidRequestError
├── RateLimitError
├── ServerError
├── NetworkError
└── FileNotFoundError

Exception Types

NovelAIError

Base class for all SDK errors.

typescript
import { NovelAIError } from 'novelai-sdk-unofficial';

try {
  // SDK operation
} catch (error) {
  if (error instanceof NovelAIError) {
    console.error('SDK error:', error.message);
  }
}

MissingAPIKeyError

Thrown when no API key is provided.

typescript
import { NovelAI, MissingAPIKeyError } from 'novelai-sdk-unofficial';

try {
  const client = new NovelAI(); // No key, no env var
} catch (error) {
  if (error instanceof MissingAPIKeyError) {
    console.error('Please set NOVELAI_API_KEY or provide apiKey option');
  }
}

AuthenticationError

Thrown for authentication failures (HTTP 401, 402).

  • Invalid API key
  • Expired API key
  • Insufficient credits/subscription
typescript
import { AuthenticationError } from 'novelai-sdk-unofficial';

try {
  await client.image.generate({ prompt: 'test' });
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Check your API key and subscription status');
  }
}

InvalidRequestError

Thrown for invalid request parameters (HTTP 400).

typescript
import { InvalidRequestError } from 'novelai-sdk-unofficial';

try {
  await client.image.generate({
    prompt: 'test',
    size: [100, 100], // Invalid: not multiple of 64
  });
} catch (error) {
  if (error instanceof InvalidRequestError) {
    console.error('Invalid parameters:', error.message);
  }
}

RateLimitError

Thrown when rate limit is exceeded (HTTP 429).

typescript
import { RateLimitError } from 'novelai-sdk-unofficial';

try {
  await client.image.generate({ prompt: 'test' });
} catch (error) {
  if (error instanceof RateLimitError) {
    console.error('Rate limited. Please wait before retrying.');
    // Implement backoff strategy
  }
}

ServerError

Thrown for server-side errors (HTTP 5xx).

typescript
import { ServerError } from 'novelai-sdk-unofficial';

try {
  await client.image.generate({ prompt: 'test' });
} catch (error) {
  if (error instanceof ServerError) {
    console.error('Server error. Try again later.');
  }
}

NetworkError

Thrown for network-related failures.

  • Connection timeout
  • DNS resolution failure
  • Connection refused
typescript
import { NetworkError } from 'novelai-sdk-unofficial';

try {
  await client.image.generate({ prompt: 'test' });
} catch (error) {
  if (error instanceof NetworkError) {
    console.error('Network error. Check your connection.');
  }
}

FileNotFoundError

Thrown when a referenced file doesn't exist.

typescript
import { FileNotFoundError } from 'novelai-sdk-unofficial';

try {
  // If using file path that doesn't exist
} catch (error) {
  if (error instanceof FileNotFoundError) {
    console.error('File not found:', error.message);
  }
}

Comprehensive Error Handling

typescript
import {
  NovelAI,
  NovelAIError,
  MissingAPIKeyError,
  AuthenticationError,
  InvalidRequestError,
  RateLimitError,
  ServerError,
  NetworkError,
} from 'novelai-sdk-unofficial';

async function generateImage(prompt: string) {
  try {
    const client = new NovelAI();
    const images = await client.image.generate({ prompt });
    return images[0];
  } catch (error) {
    if (error instanceof MissingAPIKeyError) {
      throw new Error('Configuration error: API key not set');
    }
    
    if (error instanceof AuthenticationError) {
      throw new Error('Authentication failed: Check API key');
    }
    
    if (error instanceof InvalidRequestError) {
      throw new Error(`Invalid request: ${error.message}`);
    }
    
    if (error instanceof RateLimitError) {
      // Could implement retry with backoff
      throw new Error('Rate limited: Try again later');
    }
    
    if (error instanceof ServerError) {
      throw new Error('Server error: Service temporarily unavailable');
    }
    
    if (error instanceof NetworkError) {
      throw new Error('Network error: Check connection');
    }
    
    if (error instanceof NovelAIError) {
      throw new Error(`SDK error: ${error.message}`);
    }
    
    throw error; // Re-throw unknown errors
  }
}

Retry Strategy

Example with exponential backoff for rate limits:

typescript
async function generateWithRetry(
  prompt: string,
  maxRetries: number = 3
): Promise<Buffer> {
  let lastError: Error | undefined;
  
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const images = await client.image.generate({ prompt });
      return images[0];
    } catch (error) {
      if (error instanceof RateLimitError) {
        lastError = error;
        const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s
        console.log(`Rate limited. Retrying in ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error; // Don't retry other errors
    }
  }
  
  throw lastError;
}

Validation Errors

The SDK uses Zod for parameter validation. Invalid parameters throw ZodError:

typescript
import { z } from 'zod';

try {
  await client.image.generate({
    prompt: '', // Empty prompt
  });
} catch (error) {
  if (error instanceof z.ZodError) {
    console.error('Validation errors:');
    error.errors.forEach(e => {
      console.error(`  ${e.path.join('.')}: ${e.message}`);
    });
  }
}

Released under the MIT License.