Skip to content

错误处理

SDK 为不同的错误场景提供了类型化的异常类。

异常层次结构

text
NovelAIError (基类)
├── MissingAPIKeyError
├── AuthenticationError
├── InvalidRequestError
├── RateLimitError
├── ServerError
├── NetworkError
└── FileNotFoundError

异常类型

NovelAIError

所有 SDK 错误的基类。

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

try {
  // SDK 操作
} catch (error) {
  if (error instanceof NovelAIError) {
    console.error('SDK 错误:', error.message);
  }
}

MissingAPIKeyError

未提供 API Key 时抛出。

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

try {
  const client = new NovelAI(); // 无 Key,无环境变量
} catch (error) {
  if (error instanceof MissingAPIKeyError) {
    console.error('请设置 NOVELAI_API_KEY 或提供 apiKey 选项');
  }
}

AuthenticationError

身份认证失败时抛出(HTTP 401、402)。

  • API Key 无效
  • API Key 已过期
  • 积分/订阅不足
typescript
import { AuthenticationError } from 'novelai-sdk-unofficial';

try {
  await client.image.generate({ prompt: 'test' });
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('请检查 API Key 和订阅状态');
  }
}

InvalidRequestError

请求参数无效时抛出(HTTP 400)。

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

try {
  await client.image.generate({
    prompt: 'test',
    size: [100, 100], // 无效:不是 64 的倍数
  });
} catch (error) {
  if (error instanceof InvalidRequestError) {
    console.error('参数无效:', error.message);
  }
}

RateLimitError

超出速率限制时抛出(HTTP 429)。

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

try {
  await client.image.generate({ prompt: 'test' });
} catch (error) {
  if (error instanceof RateLimitError) {
    console.error('请求过于频繁,请稍后重试');
    // 实现退避策略
  }
}

ServerError

服务器端错误时抛出(HTTP 5xx)。

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

try {
  await client.image.generate({ prompt: 'test' });
} catch (error) {
  if (error instanceof ServerError) {
    console.error('服务器错误,请稍后重试');
  }
}

NetworkError

网络相关故障时抛出。

  • 连接超时
  • DNS 解析失败
  • 连接被拒绝
typescript
import { NetworkError } from 'novelai-sdk-unofficial';

try {
  await client.image.generate({ prompt: 'test' });
} catch (error) {
  if (error instanceof NetworkError) {
    console.error('网络错误,请检查连接');
  }
}

FileNotFoundError

引用的文件不存在时抛出。

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

try {
  // 如果使用的文件路径不存在
} catch (error) {
  if (error instanceof FileNotFoundError) {
    console.error('文件未找到:', error.message);
  }
}

完整的错误处理示例

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('配置错误:未设置 API Key');
    }
    
    if (error instanceof AuthenticationError) {
      throw new Error('认证失败:请检查 API Key');
    }
    
    if (error instanceof InvalidRequestError) {
      throw new Error(`请求无效:${error.message}`);
    }
    
    if (error instanceof RateLimitError) {
      // 可以实现带退避的重试
      throw new Error('请求过于频繁:请稍后重试');
    }
    
    if (error instanceof ServerError) {
      throw new Error('服务器错误:服务暂时不可用');
    }
    
    if (error instanceof NetworkError) {
      throw new Error('网络错误:请检查连接');
    }
    
    if (error instanceof NovelAIError) {
      throw new Error(`SDK 错误:${error.message}`);
    }
    
    throw error; // 重新抛出未知错误
  }
}

重试策略

带指数退避的速率限制重试示例:

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(`请求受限,${delay}ms 后重试...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      throw error; // 其他错误不重试
    }
  }
  
  throw lastError;
}

验证错误

SDK 使用 Zod 进行参数验证。无效参数会抛出 ZodError

typescript
import { z } from 'zod';

try {
  await client.image.generate({
    prompt: '', // 空提示词
  });
} catch (error) {
  if (error instanceof z.ZodError) {
    console.error('验证错误:');
    error.errors.forEach(e => {
      console.error(`  ${e.path.join('.')}: ${e.message}`);
    });
  }
}

基于 MIT 许可证发布