New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

ai-json-safe-parse

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ai-json-safe-parse

Parse malformed JSON from AI/LLM responses. Handles markdown code blocks, trailing commas, comments, unquoted keys, and more.

latest
Source
npmnpm
Version
0.3.0
Version published
Weekly downloads
13
-45.83%
Maintainers
1
Weekly downloads
 
Created
Source

ai-json-safe-parse

npm version license bundle size

Parse malformed JSON from AI/LLM responses. Zero dependencies. Works in Node.js and browsers.

If you've built anything with ChatGPT, Claude, Gemini, or any other LLM, you've hit this: you ask for JSON and get back something that almost works — wrapped in markdown code blocks, sprinkled with trailing commas, decorated with smart quotes, or buried in a paragraph of explanation. JSON.parse chokes and your app breaks.

ai-json-safe-parse handles all of it. One function call, typed generics, no dependencies.

Install

npm install ai-json-safe-parse

Works with any package manager (npm, yarn, pnpm, bun) and any runtime (Node.js, browsers, Deno, Cloudflare Workers, edge functions).

Quick Start

import { aiJsonParse } from 'ai-json-safe-parse'

// Typical LLM response with markdown code fences
const llmOutput = `Sure! Here's the JSON:

\`\`\`json
{
  "sentiment": "positive",
  "confidence": 0.95,
  "keywords": ["great", "excellent", "loved it"]
}
\`\`\`

Let me know if you need anything else!`

const result = aiJsonParse<{
  sentiment: string
  confidence: number
  keywords: string[]
}>(llmOutput)

if (result.success) {
  console.log(result.data.sentiment) // "positive"
  console.log(result.data.confidence) // 0.95
}

API

The library exports three functions. Pick the one that fits your error-handling style.

aiJsonParse<T>(text, options?) — Result object

Returns a discriminated union: { success: true, data: T } or { success: false, error: string }. Never throws.

import { aiJsonParse } from 'ai-json-safe-parse'

const result = aiJsonParse<{ name: string }>(llmOutput)

if (result.success) {
  console.log(result.data.name)
} else {
  console.error(result.error)
}

aiJsonSafeParse<T>(text, options?) — Nullable

Returns the parsed value or null. The simplest option when you just need the data.

import { aiJsonSafeParse } from 'ai-json-safe-parse'

const data = aiJsonSafeParse<{ name: string }>(llmOutput)
if (data) {
  console.log(data.name)
}

You can also pass a fallback value — if parsing fails, you get the fallback instead of null:

const data = aiJsonSafeParse(llmOutput, { name: 'unknown' })
// data is always { name: string }, never null

aiJsonStrictParse<T>(text, options?) — Throws on failure

Returns the parsed value or throws an Error. Use this when a parse failure should be exceptional.

import { aiJsonStrictParse } from 'ai-json-safe-parse'

const data = aiJsonStrictParse<{ name: string }>(llmOutput)
console.log(data.name)

What It Fixes

The parser applies recovery strategies in order, from safest to most aggressive:

StrategyModeWhat it handles
Direct JSON.parsebothAlready-valid JSON
Markdown extractionboth```json ... ```, ```jsonc ... ```, ```js ... ```, and bare code blocks
Unicode normalizationbothUTF-8 BOM, zero-width chars, smart quotes \u201C\u201D\u2018\u2019, em/en dashes \u2014\u2013, non-breaking spaces, ellipsis \u2026
Bracket matchingbothJSON embedded in prose: "Here is the result: {...} hope that helps!"
Comment removalaggressive// line comments and /* block comments */ (preserves URLs)
Trailing comma removalaggressive{"a": 1,} and [1, 2,]
Single quote replacementaggressive{'name': 'Alice'}
Unquoted key fixaggressive{name: "Alice"}
Regex key-value extractionaggressiveSeverely broken JSON (last resort)

Real-world examples this handles

// Markdown code blocks
aiJsonParse('```json\n{"key": "value"}\n```')

// JSON buried in a paragraph
aiJsonParse('The analysis shows {"score": 95, "grade": "A"} for this input.')

// Trailing commas (extremely common from LLMs)
aiJsonParse('{"items": ["a", "b", "c",],}')

// JavaScript-style objects with comments
aiJsonParse(`{
  name: "Alice",       // the user
  age: 30,             // in years
  active: true,
}`)

// Smart quotes from copy-paste or GPT
aiJsonParse('{\u201Cname\u201D: \u201CAlice\u201D}')

// Em dashes in content
aiJsonParse('{"range": "10\u201420"}')  // → {"range": "10-20"}

Options

interface ParseOptions {
  /**
   * How aggressively to attempt repairs on malformed JSON.
   * Default: 'aggressive'
   */
  mode?: 'safe' | 'aggressive'
}

safe — Tries direct parse, markdown extraction, unicode normalization, and bracket matching only. Use this when data integrity is more important than recovery rate. Won't modify the JSON structure.

aggressive (default) — Additionally fixes syntax issues and falls back to regex extraction. Higher recovery rate, but may misinterpret severely malformed input.

// Only use safe recovery strategies
const result = aiJsonParse(text, { mode: 'safe' })

// Use all strategies (default)
const result = aiJsonParse(text, { mode: 'aggressive' })

TypeScript

Full generic type support. All exports are fully typed.

import { aiJsonParse, aiJsonSafeParse, aiJsonStrictParse } from 'ai-json-safe-parse'
import type { ParseResult, ParseSuccess, ParseFailure, ParseOptions } from 'ai-json-safe-parse'

interface MyResponse {
  summary: string
  score: number
  tags: string[]
}

// All three functions accept a generic type parameter
const result = aiJsonParse<MyResponse>(text)       // ParseResult<MyResponse>
const data = aiJsonSafeParse<MyResponse>(text)     // MyResponse | null
const strict = aiJsonStrictParse<MyResponse>(text) // MyResponse (throws on failure)

Bundle Size

Zero dependencies. Tree-shakeable ESM. The entire library is ~5KB unminified (~2KB gzipped).

Both ESM (import) and CommonJS (require) are supported via the exports field in package.json.

Background

This library was extracted from the production codebase at LeadTruffle, where we use it to parse thousands of AI-generated JSON responses daily across our lead qualification, SMS automation, and voice AI pipelines. We run it in AWS Lambda (Node.js), Cloudflare Workers, and in-browser — so it had to be lightweight, dependency-free, and universal from day one.

After copy-pasting variations of this code across multiple services, it made sense to clean it up and share it. Thank you to LeadTruffle for supporting the open-source release.

Testing

The test suite covers valid JSON, markdown extraction, unicode edge cases, bracket matching, all aggressive-mode fixes, safe mode, real-world LLM outputs, and error cases.

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Type check
npm run lint

Tests use Vitest. To run them locally:

git clone https://github.com/a-r-d/ai-json-safe-parse.git
cd ai-json-safe-parse
npm install
npm test

Contributing

Contributions are welcome! If you've hit an LLM output format that this library doesn't handle, please open an issue with the raw text — that's the most helpful thing you can provide.

To contribute code:

  • Fork the repo and create a branch
  • Add a failing test for the case you're fixing
  • Implement the fix
  • Run npm test to make sure everything passes
  • Run npm run lint to check types
  • Open a PR

Please keep PRs focused — one fix or feature per PR.

Author

Aaron Deckerard.ninja / @a-r-d

CTO at LeadTruffle, a speed-to-lead platform for home service businesses. I've been a software engineer for 15+ years. After writing the same JSON-from-LLM parsing code across too many services, I decided to open source it. If you're building AI-powered products and burning time on malformed JSON, I hope this saves you some headaches.

License

MIT

Keywords

json

FAQs

Package last updated on 22 Mar 2026

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts