Skip to main content
Beta: Front-End Checklist is currently in beta. Some issues are still being fixed. Thanks for your patience.

Parse JSON safely with error handling

Always wrap JSON.parse() in try/catch and validate the parsed structure before use, as invalid JSON or unexpected data shapes cause runtime errors.

Utilities
Quick take
Typical fix time 10 min
  • JSON.parse() throws a SyntaxError on invalid input — always use try/catch
  • Validate the shape of parsed data before accessing its properties
  • JSON.stringify() can return undefined for values that can't be serialized
  • Use a type-safe parser (Zod, Valibot) for data from external sources
Why it matters: JSON.parse() on invalid input throws a SyntaxError that will crash your application if uncaught. API responses, localStorage values, and user-provided data can all be malformed. Safe parsing with validation catches these errors at the point of parsing, not deep in your application logic when a missing property causes an unexpected error.

Rule Details

JSON.parse() is a common source of uncaught exceptions when data comes from external, user-controlled, or cached sources.

Code Example

// ❌ Throws SyntaxError if input is invalid
const data = JSON.parse(input)
 
// ✅ Always wrap in try/catch
function safeParse(json, fallback = null) {
  try {
    return JSON.parse(json)
  } catch {
    return fallback
  }
}
 
const config = safeParse(localStorage.getItem('config'), {})

Why It Matters

JSON.parse() on invalid input throws a SyntaxError that will crash your application if uncaught. API responses, localStorage values, and user-provided data can all be malformed. Safe parsing with validation catches these errors at the point of parsing, not deep in your application logic when a missing property causes an unexpected error.

Validating the Shape

// Just parsing isn't enough — the shape might be wrong
const raw = JSON.parse(apiResponse)
const name = raw.user.profile.name // TypeError if any property is missing!
 
// ✅ Validate before use
function parseUserResponse(json) {
  try {
    const data = JSON.parse(json)
    if (typeof data?.user?.profile?.name !== 'string') {
      throw new Error('Invalid user response shape')
    }
    return data
  } catch (error) {
    console.error('Failed to parse user response:', error)
    return null
  }
}

Using Zod for Schema Validation

import { z } from 'zod'
 
const UserSchema = z.object({
  id: z.number(),
  name: z.string(),
  email: z.string().email(),
  role: z.enum(['admin', 'user', 'moderator'])
})
 
function parseUser(json) {
  try {
    const raw = JSON.parse(json)
    return UserSchema.parse(raw) // Throws ZodError if shape is wrong
  } catch (error) {
    console.error('User parsing failed:', error)
    return null
  }
}
 
// Or use safeParse which returns { success, data, error }
const result = UserSchema.safeParse(raw)
if (result.success) {
  processUser(result.data) // Fully typed!
}

JSON.stringify Edge Cases

// Some values become undefined in JSON.stringify:
JSON.stringify(undefined)           // undefined (not a string!)
JSON.stringify({ a: undefined })    // '{}' — property dropped!
JSON.stringify({ fn: () => {} })    // '{}' — functions dropped!
JSON.stringify(new Date())          // '"2024-01-15T..."' — serialized as string
JSON.stringify(new Map([[1, 2]]))   // '{}' — Maps don't serialize!
 
// Safe serialization
function safeStringify(value, fallback = '{}') {
  try {
    const result = JSON.stringify(value)
    return result ?? fallback
  } catch {
    return fallback
  }
}

Parsing API Responses

async function fetchData(url) {
  const response = await fetch(url)
  if (!response.ok) {
    throw new Error(`HTTP error: ${response.status}`)
  }
 
  // response.json() already does JSON.parse() + try/catch
  // But it throws on non-JSON content types
  const contentType = response.headers.get('content-type')
  if (!contentType?.includes('application/json')) {
    throw new Error('Response is not JSON')
  }
 
  return response.json()
}

Standards

  • Use MDN: JavaScript Guide as the standard for how this JavaScript pattern should behave in production, not just in a small local example.
  • Use web.dev: Learn JavaScript as the standard for how this JavaScript pattern should behave in production, not just in a small local example.

Verification

Automated Checks

  • Verify the behavior in the browser after the code change, not only in static analysis.
  • Inspect DevTools Network or Performance panels when the rule affects loading or execution order.
  • Test the primary user flow and one edge case triggered by the changed script path.

Manual Checks

  • Confirm the code still behaves correctly when the feature is delayed, lazy-loaded, or fails.

Use with AI

Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.

Check

Verify implementation

Find all JSON.parse() calls in this file and check whether each one is wrapped in try/catch and whether the result is validated before use.

Fix

Auto-fix issues

Add try/catch error handling to all JSON.parse() calls and add shape validation to protect against unexpected data structures.

Explain

Learn more

Explain why JSON.parse can throw, what safe JSON parsing looks like, and when to use schema validation libraries.

Review

Code review

Review scripts, client components, and browser execution paths related to Parse JSON safely with error handling. Flag exact imports, event handlers, runtime side effects, or blocking operations that violate the rule, and state how the change should be verified in the browser.

Sources

References used to support the guidance in this rule.

Further Reading

Tools and supplementary material for exploring the topic in more depth.

Rules that often go hand-in-hand with this one.

Use Web Storage API safely

Use localStorage and sessionStorage with proper serialization, error handling, and security awareness to avoid data corruption and storage quota errors.

JavaScript
Never use eval() or unsafe dynamic code execution

Avoid eval(), new Function(), setTimeout/setInterval with string arguments, and innerHTML with untrusted content — they execute arbitrary code and create critical XSS vulnerabilities.

JavaScript
Implement proper error handling

Use try-catch blocks and error boundaries to gracefully handle errors in async operations and UI components.

JavaScript
Enable noUncheckedIndexedAccess to catch out-of-bounds array bugs

Enable noUncheckedIndexedAccess in tsconfig.json to make array and object index access return T | undefined, forcing explicit null checks that prevent out-of-bounds runtime errors.

JavaScript

Was this rule helpful?

Your feedback helps improve rule quality. This stays internal for now.

Loading feedback...
0 / 385