llm-errors 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (26) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +14 -0
  3. package/fixtures/README.md +25 -0
  4. package/fixtures/cases/anthropic/fetch-context-length.json +17 -0
  5. package/fixtures/cases/anthropic/fetch-rate-limit.json +18 -0
  6. package/fixtures/cases/anthropic/sdk-overloaded-529.json +17 -0
  7. package/fixtures/cases/gemini/fetch-unavailable.json +19 -0
  8. package/fixtures/cases/gemini/rpc-permission-denied.json +11 -0
  9. package/fixtures/cases/gemini/rpc-resource-exhausted.json +17 -0
  10. package/fixtures/cases/network/abort-error.json +8 -0
  11. package/fixtures/cases/network/node-timeout.json +9 -0
  12. package/fixtures/cases/openai/fetch-context-length.json +18 -0
  13. package/fixtures/cases/openai/sdk-insufficient-quota.json +13 -0
  14. package/fixtures/cases/openai/sdk-rate-limit.json +18 -0
  15. package/fixtures/expected/anthropic/fetch-context-length.json +8 -0
  16. package/fixtures/expected/anthropic/fetch-rate-limit.json +9 -0
  17. package/fixtures/expected/anthropic/sdk-overloaded-529.json +8 -0
  18. package/fixtures/expected/gemini/fetch-unavailable.json +9 -0
  19. package/fixtures/expected/gemini/rpc-permission-denied.json +8 -0
  20. package/fixtures/expected/gemini/rpc-resource-exhausted.json +9 -0
  21. package/fixtures/expected/network/abort-error.json +7 -0
  22. package/fixtures/expected/network/node-timeout.json +7 -0
  23. package/fixtures/expected/openai/fetch-context-length.json +8 -0
  24. package/fixtures/expected/openai/sdk-insufficient-quota.json +8 -0
  25. package/fixtures/expected/openai/sdk-rate-limit.json +9 -0
  26. package/package.json +2 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres
5
5
  to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.1.4] - 2026-06-05
8
+
9
+ ### Added
10
+
11
+ - Added a public provider error fixture corpus for OpenAI, Anthropic, Gemini and
12
+ transport-level failures, covering SDK-like objects, parsed fetch responses
13
+ and expected normalized outputs.
14
+ - Added fixture-driven regression tests and published `fixtures/` in the npm
15
+ package.
16
+
7
17
  ## [0.1.3] - 2026-06-04
8
18
 
9
19
  ### Changed
@@ -44,4 +54,8 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
44
54
  pair arrays.
45
55
  - Zero runtime dependencies; ESM + CJS builds with type declarations.
46
56
 
57
+ [0.1.4]: https://github.com/slegarraga/llm-errors/releases/tag/v0.1.4
58
+ [0.1.3]: https://github.com/slegarraga/llm-errors/releases/tag/v0.1.3
59
+ [0.1.2]: https://github.com/slegarraga/llm-errors/releases/tag/v0.1.2
60
+ [0.1.1]: https://github.com/slegarraga/llm-errors/releases/tag/v0.1.1
47
61
  [0.1.0]: https://github.com/slegarraga/llm-errors/releases/tag/v0.1.0
package/README.md CHANGED
@@ -9,6 +9,9 @@
9
9
 
10
10
  > Normalize OpenAI, Anthropic and Gemini API errors into one shape: category, retryable flag and `Retry-After` delay. **Zero dependencies.**
11
11
 
12
+ Security posture is tracked in [docs/security-posture.md](./docs/security-posture.md),
13
+ including CodeQL, OpenSSF Scorecard, Dependabot and branch rules.
14
+
12
15
  Every LLM provider fails differently. OpenAI nests `{ error: { type, code, param } }`, Anthropic wraps `{ type: "error", error: { type } }`, Gemini speaks Google RPC status strings, and each puts retry hints in a different place. `llm-errors` collapses all of that into a single, predictable object so your retry and error-handling code stays provider-agnostic.
13
16
 
14
17
  ```ts
@@ -41,6 +44,17 @@ try {
41
44
  npm install llm-errors
42
45
  ```
43
46
 
47
+ ## Fixture corpus
48
+
49
+ The npm package includes a public fixture corpus under
50
+ [`fixtures/`](./fixtures/README.md). It pairs raw SDK-like, fetch-like and
51
+ transport-level provider errors with the normalized output expected from
52
+ `normalizeError`.
53
+
54
+ These fixtures are useful for downstream regression tests when you want to
55
+ verify provider-portable retry and error handling without importing OpenAI,
56
+ Anthropic or Gemini SDKs.
57
+
44
58
  ## API
45
59
 
46
60
  ### `normalizeError(error, options?) => NormalizedError`
@@ -0,0 +1,25 @@
1
+ # Provider Error Fixtures
2
+
3
+ This corpus contains redacted, synthetic examples of provider error shapes that
4
+ `llm-errors` supports. The files are intentionally small JSON fixtures so they
5
+ can be reused by downstream test suites without importing any provider SDK.
6
+
7
+ ## Layout
8
+
9
+ - `cases/` contains raw SDK-like, fetch-like and transport-level inputs.
10
+ - `expected/` contains the normalized output for the matching case path.
11
+
12
+ For example, `cases/openai/sdk-rate-limit.json` is paired with
13
+ `expected/openai/sdk-rate-limit.json`.
14
+
15
+ ## Scope
16
+
17
+ The corpus covers:
18
+
19
+ - OpenAI SDK `APIError`-style objects and parsed fetch responses.
20
+ - Anthropic SDK envelopes and parsed fetch responses.
21
+ - Gemini / Google RPC error envelopes.
22
+ - Transport failures such as Node timeout codes and browser abort errors.
23
+
24
+ The fixtures are not recordings of private traffic and do not contain API keys,
25
+ request IDs, account IDs or user content.
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "Anthropic parsed fetch response prompt too long",
3
+ "shape": "anthropic-fetch-parsed-body",
4
+ "error": {
5
+ "status": 400,
6
+ "headers": {
7
+ "anthropic-version": "2023-06-01"
8
+ },
9
+ "body": {
10
+ "type": "error",
11
+ "error": {
12
+ "type": "invalid_request_error",
13
+ "message": "prompt is too long: 250000 tokens > 200000 maximum"
14
+ }
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "Anthropic parsed fetch response rate limit",
3
+ "shape": "anthropic-fetch-parsed-body",
4
+ "error": {
5
+ "status": 429,
6
+ "headers": {
7
+ "anthropic-ratelimit-requests-limit": "50",
8
+ "retry-after": "30"
9
+ },
10
+ "body": {
11
+ "type": "error",
12
+ "error": {
13
+ "type": "rate_limit_error",
14
+ "message": "rate limit exceeded"
15
+ }
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "Anthropic SDK overloaded response",
3
+ "shape": "anthropic-sdk-apierror",
4
+ "error": {
5
+ "status": 529,
6
+ "headers": {
7
+ "anthropic-version": "2023-06-01"
8
+ },
9
+ "error": {
10
+ "type": "error",
11
+ "error": {
12
+ "type": "overloaded_error",
13
+ "message": "Overloaded"
14
+ }
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "Gemini parsed fetch response unavailable",
3
+ "shape": "google-rpc-fetch-parsed-body",
4
+ "error": {
5
+ "response": {
6
+ "status": 503,
7
+ "headers": {
8
+ "retry-after": "4"
9
+ },
10
+ "data": {
11
+ "error": {
12
+ "code": 503,
13
+ "message": "The model is overloaded. Please try again later.",
14
+ "status": "UNAVAILABLE"
15
+ }
16
+ }
17
+ }
18
+ }
19
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "Gemini Google RPC permission denied",
3
+ "shape": "google-rpc-error-envelope",
4
+ "error": {
5
+ "error": {
6
+ "code": 403,
7
+ "message": "The caller does not have permission.",
8
+ "status": "PERMISSION_DENIED"
9
+ }
10
+ }
11
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "Gemini Google RPC resource exhausted",
3
+ "shape": "google-rpc-error-envelope",
4
+ "error": {
5
+ "error": {
6
+ "code": 429,
7
+ "message": "Resource has been exhausted.",
8
+ "status": "RESOURCE_EXHAUSTED",
9
+ "details": [
10
+ {
11
+ "@type": "type.googleapis.com/google.rpc.RetryInfo",
12
+ "retryDelay": "17s"
13
+ }
14
+ ]
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "Browser fetch abort",
3
+ "shape": "dom-abort-error",
4
+ "error": {
5
+ "name": "AbortError",
6
+ "message": "The operation was aborted."
7
+ }
8
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "Node transport timeout",
3
+ "shape": "node-error-code",
4
+ "error": {
5
+ "name": "Error",
6
+ "message": "connect ETIMEDOUT",
7
+ "code": "ETIMEDOUT"
8
+ }
9
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "OpenAI parsed fetch response context length",
3
+ "shape": "openai-fetch-parsed-body",
4
+ "error": {
5
+ "status": 400,
6
+ "headers": {
7
+ "openai-processing-ms": "42"
8
+ },
9
+ "body": {
10
+ "error": {
11
+ "message": "This model's maximum context length is 128000 tokens.",
12
+ "type": "invalid_request_error",
13
+ "code": "context_length_exceeded",
14
+ "param": "messages"
15
+ }
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "OpenAI SDK APIError insufficient quota",
3
+ "shape": "openai-sdk-apierror",
4
+ "error": {
5
+ "status": 429,
6
+ "error": {
7
+ "message": "You exceeded your current quota.",
8
+ "type": "insufficient_quota",
9
+ "code": "insufficient_quota",
10
+ "param": null
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "OpenAI SDK APIError rate limit",
3
+ "shape": "openai-sdk-apierror",
4
+ "error": {
5
+ "status": 429,
6
+ "headers": {
7
+ "openai-version": "2020-10-01",
8
+ "retry-after-ms": "1250",
9
+ "retry-after": "2"
10
+ },
11
+ "error": {
12
+ "message": "Rate limit reached for requests",
13
+ "type": "rate_limit_error",
14
+ "code": "rate_limit_exceeded",
15
+ "param": null
16
+ }
17
+ }
18
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "provider": "anthropic",
3
+ "category": "context_length_exceeded",
4
+ "message": "prompt is too long: 250000 tokens > 200000 maximum",
5
+ "status": 400,
6
+ "code": "invalid_request_error",
7
+ "retryable": false
8
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "provider": "anthropic",
3
+ "category": "rate_limit",
4
+ "message": "rate limit exceeded",
5
+ "status": 429,
6
+ "code": "rate_limit_error",
7
+ "retryable": true,
8
+ "retryAfterMs": 30000
9
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "provider": "anthropic",
3
+ "category": "overloaded",
4
+ "message": "Overloaded",
5
+ "status": 529,
6
+ "code": "overloaded_error",
7
+ "retryable": true
8
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "provider": "gemini",
3
+ "category": "overloaded",
4
+ "message": "The model is overloaded. Please try again later.",
5
+ "status": 503,
6
+ "code": "UNAVAILABLE",
7
+ "retryable": true,
8
+ "retryAfterMs": 4000
9
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "provider": "gemini",
3
+ "category": "permission",
4
+ "message": "The caller does not have permission.",
5
+ "status": 403,
6
+ "code": "PERMISSION_DENIED",
7
+ "retryable": false
8
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "provider": "gemini",
3
+ "category": "rate_limit",
4
+ "message": "Resource has been exhausted.",
5
+ "status": 429,
6
+ "code": "RESOURCE_EXHAUSTED",
7
+ "retryable": true,
8
+ "retryAfterMs": 17000
9
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "provider": "unknown",
3
+ "category": "timeout",
4
+ "message": "The operation was aborted.",
5
+ "code": "AbortError",
6
+ "retryable": true
7
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "provider": "unknown",
3
+ "category": "timeout",
4
+ "message": "connect ETIMEDOUT",
5
+ "code": "ETIMEDOUT",
6
+ "retryable": true
7
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "provider": "openai",
3
+ "category": "context_length_exceeded",
4
+ "message": "This model's maximum context length is 128000 tokens.",
5
+ "status": 400,
6
+ "code": "context_length_exceeded",
7
+ "retryable": false
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "provider": "openai",
3
+ "category": "insufficient_quota",
4
+ "message": "You exceeded your current quota.",
5
+ "status": 429,
6
+ "code": "insufficient_quota",
7
+ "retryable": false
8
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "provider": "openai",
3
+ "category": "rate_limit",
4
+ "message": "Rate limit reached for requests",
5
+ "status": 429,
6
+ "code": "rate_limit_exceeded",
7
+ "retryable": true,
8
+ "retryAfterMs": 1250
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llm-errors",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Normalize OpenAI, Anthropic and Gemini API errors into one shape: category, retryable flag and Retry-After delay. Zero dependencies.",
5
5
  "keywords": [
6
6
  "openai",
@@ -46,6 +46,7 @@
46
46
  },
47
47
  "files": [
48
48
  "dist",
49
+ "fixtures",
49
50
  "README.md",
50
51
  "LICENSE",
51
52
  "CHANGELOG.md"