Error Injection

Test your application's error handling with one-shot errors, stream truncation, and timed disconnects. llmock provides three mechanisms for simulating failures.

One-Shot Errors

Queue an error that fires on the next request and auto-removes itself. Useful for testing retry logic.

one-shot-error.test.ts ts
const mock = new LLMock();
await mock.start();
mock.onMessage("hello", { content: "Hi!" });

// Queue a 429 rate limit error for the next request
mock.nextRequestError(429, {
  message: "Rate limit exceeded",
  type: "rate_limit_error",
});

// First request → 429 error
const res1 = await fetch(`${mock.url}/v1/chat/completions`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    model: "gpt-4",
    messages: [{ role: "user", content: "hello" }],
  }),
});
expect(res1.status).toBe(429);

// Second request → normal response (error auto-removed)
const res2 = await fetch(`${mock.url}/v1/chat/completions`, { /* same */ });
expect(res2.status).toBe(200);

Stream Truncation

Abort a streaming response after a specific number of SSE chunks. Tests that your application handles partial streams gracefully.

truncation.test.ts ts
mock.on(
  { userMessage: "long story" },
  { content: "This is a very long response that will be cut short" },
  { truncateAfterChunks: 3 }  // Abort after 3 SSE chunks
);

Timed Disconnect

Disconnect after a specified number of milliseconds. Simulates network timeouts and connection drops.

disconnect.test.ts ts
mock.on(
  { userMessage: "slow" },
  { content: "This response will never complete" },
  { disconnectAfterMs: 100 }  // Kill connection after 100ms
);

Error Fixtures in JSON

fixtures/errors.json json
{
  "fixtures": [
    {
      "match": { "userMessage": "error-test" },
      "response": {
        "error": {
          "message": "Rate limited",
          "type": "rate_limit_error"
        },
        "status": 429
      }
    },
    {
      "match": { "userMessage": "partial" },
      "response": { "content": "This gets cut off" },
      "truncateAfterChunks": 2
    },
    {
      "match": { "userMessage": "timeout" },
      "response": { "content": "Never finishes" },
      "disconnectAfterMs": 50
    }
  ]
}

Interruption Behavior

nextRequestError() is one-shot: it fires once and auto-removes itself. For persistent error fixtures, use addFixture() with an error response.