Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool

JSON Parse Errors in Different Programming Languages

JSON has become the universal language for data interchange, but each programming language handles JSON parsing errors differently. Understanding these differences is crucial when debugging JSON issues in various environments or when building cross-language systems.

This article explores how major programming languages detect, report, and handle JSON parsing errors, providing examples and best practices for each language.

JavaScript

As the language JSON was designed for, JavaScript provides native parsing but with relatively sparse error information.

Parsing Mechanism

  • Uses the native JSON.parse() method
  • Throws SyntaxError on invalid JSON
  • Error message includes only character position, not line numbers
  • No built-in mechanism to display the problematic part of JSON

Basic JavaScript Parsing:

try {
  const data = JSON.parse('{"name": "JavaScript", "version": 2023,}'); // Invalid - trailing comma
} catch (error) {
  console.error('JSON parse error:', error.message);
  // Output: "JSON parse error: Unexpected token } in JSON at position 39"
}

Enhanced Error Handling:

function parseWithContext(jsonString) {
  try {
    return { data: JSON.parse(jsonString), error: null };
  } catch (error) {
    // Extract position from error message
    const posMatch = error.message.match(/at position (\d+)/);
    const position = posMatch ? parseInt(posMatch[1], 10) : -1;
    
    // Provide visual context for the error
    let errorContext = '';
    if (position >= 0) {
      const start = Math.max(0, position - 20);
      const end = Math.min(jsonString.length, position + 20);
      const excerpt = jsonString.substring(start, end);
      
      // Calculate the position within our excerpt
      const pointerPos = position - start;
      
      errorContext = `
Context:
  ${excerpt.replace(/\n/g, ' ')}
  ${'~'.repeat(pointerPos)}^ Error occurs here
      `;
    }
    
    return {
      data: null,
      error: error.message,
      position: position,
      context: errorContext
    };
  }
}

const result = parseWithContext('{"name": "JavaScript", "version": 2023,}');
if (result.error) {
  console.error(`Error: ${result.error}`);
  console.log(result.context);
}

Common JavaScript JSON Errors

Error MessageLikely Cause
Unexpected token { in JSONInvalid object start, often in an unexpected place
Unexpected token : in JSONMissing or invalid property name before a colon
Unexpected end of JSON inputIncomplete JSON string, often missing closing brackets
Unexpected token } in JSONUnexpected closing brace, perhaps due to mismatched brackets
Unexpected token ' in JSONSingle quotes instead of required double quotes

Python

Python provides more detailed error information than JavaScript.

Parsing Mechanism

  • Uses the json module in the standard library
  • Main function is json.loads() (for strings) or json.load() (for files)
  • Raises json.JSONDecodeError which includes line, column, and position
  • Error message indicates what character was expected

Python Example:

import json

def parse_with_context(json_str):
    try:
        data = json.loads(json_str)
        return {'data': data, 'error': None}
    except json.JSONDecodeError as e:
        # Extract detailed error information
        error_info = {
            'message': str(e),
            'line': e.lineno,
            'column': e.colno,
            'position': e.pos
        }
        
        # Get the line with the error
        lines = json_str.split('\n')
        if 0 <= e.lineno - 1 < len(lines):
            error_line = lines[e.lineno - 1]
            pointer = ' ' * (e.colno - 1) + '^'
            
            # Include a few surrounding lines for context
            start_line = max(0, e.lineno - 3)
            end_line = min(len(lines), e.lineno + 2)
            
            context_lines = []
            for i in range(start_line, end_line):
                prefix = '-> ' if i == e.lineno - 1 else '   '
                context_lines.append(f"{prefix}{i+1}: {lines[i]}")
            
            # Add pointer line
            context_lines.insert(e.lineno - start_line + 1, '      ' + pointer)
            
            error_info['context'] = '\n'.join(context_lines)
        
        return {'data': None, 'error': error_info}

# Example usage
json_with_error = '''
{
    "name": "Python",
    "version": 3.11,
    "features": [
        "type hints",
        "async/await",
        "pattern matching",
    ]
}
'''  # Invalid JSON - trailing comma in array

result = parse_with_context(json_with_error)
if result['error']:
    print(f"Error: {result['error']['message']}")
    print(result['error']['context'])
    
    # Output:
    # Error: Expecting value delimiter: line 7 column 6 (char 109)
    #    3: {
    #    4:     "name": "Python",
    #    5:     "version": 3.11,
    #    6:     "features": [
    # ->  7:         "type hints",
    #       ^
    #    8:         "async/await",
    #    9:         "pattern matching",

Java

Java offers detailed error messages, especially with popular libraries like Jackson.

Parsing Mechanism

  • Most commonly uses the Jackson library
  • Key class is ObjectMapper with methods like readValue()
  • Throws JsonParseException with detailed location and character information
  • Exception includes full source location and expected token details

Java Example with Jackson:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonParseException;

public class JsonErrorExample {
    public static void main(String[] args) {
        String jsonWithError = "{\"name\": \"Java\", \"version\": 17,}"; // Invalid JSON - trailing comma
        
        try {
            ObjectMapper mapper = new ObjectMapper();
            Map<String, Object> data = mapper.readValue(jsonWithError, Map.class);
            System.out.println("Parsed successfully: " + data);
        } catch (JsonParseException e) {
            System.out.println("Parse error: " + e.getMessage());
            // Output includes line/column and detailed error:
            // "Parse error: Unexpected character ('}' (code 125)): expected a value at [Source: (String)"{"name": "Java", "version": 17,}"; line: 1, column: 31]"
            
            // Print only the relevant part of the message
            String message = e.getMessage();
            int atIndex = message.indexOf(" at [");
            if (atIndex > 0) {
                System.out.println("Error: " + message.substring(0, atIndex));
                System.out.println("Location: " + message.substring(atIndex));
            }
            
            // Parse location information
            int line = e.getLocation().getLineNr();
            int column = e.getLocation().getColumnNr();
            
            // Extract source and provide visual context
            String source = jsonWithError;
            if (source != null) {
                String[] lines = source.split("\n");
                if (lines.length > 0 && line <= lines.length) {
                    String errorLine = lines[line - 1];
                    StringBuilder pointer = new StringBuilder();
                    for (int i = 0; i < column - 1; i++) {
                        pointer.append(" ");
                    }
                    pointer.append("^");
                    
                    System.out.println("Context:");
                    System.out.println(errorLine);
                    System.out.println(pointer.toString());
                }
            }
        } catch (Exception e) {
            System.out.println("Other error: " + e.getMessage());
        }
    }
}

C# (.NET)

C# provides rich error information and configuration options.

Parsing Mechanism

  • Modern .NET uses System.Text.Json namespace
  • Key method is JsonSerializer.Deserialize()
  • Throws JsonException with path, line, byte position, and message
  • Offers configuration options to control parsing behavior

C# Example:

using System;
using System.Text.Json;
using System.Text.Json.Serialization;

public class JsonErrorDemo
{
    public static void Main()
    {
        string jsonWithError = @"{
    ""name"": ""C#"",
    ""version"": 10,
    ""features"": [""Records"", ""Pattern matching"",]  // Invalid - trailing comma
}";
        
        try
        {
            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
                AllowTrailingCommas = false  // For demonstration, default is false
            };
            
            var data = JsonSerializer.Deserialize<dynamic>(jsonWithError, options);
            Console.WriteLine("Successfully parsed");
        }
        catch (JsonException e)
        {
            Console.WriteLine($"JSON Error: {e.Message}");
            // Output includes line, position, and path:
            // "JSON Error: ',' is an invalid start of a value. Path: $.features[1] | LineNumber: 4 | BytePositionInLine: 44."
            
            // Extract line and position info
            int lineNumber = 0;
            int position = 0;
            string path = "";
            
            // Parse error details from message
            var lineMatch = System.Text.RegularExpressions.Regex.Match(e.Message, @"LineNumber: (d+)");
            if (lineMatch.Success)
                lineNumber = int.Parse(lineMatch.Groups[1].Value);
                
            var posMatch = System.Text.RegularExpressions.Regex.Match(e.Message, @"BytePositionInLine: (d+)");
            if (posMatch.Success)
                position = int.Parse(posMatch.Groups[1].Value);
                
            var pathMatch = System.Text.RegularExpressions.Regex.Match(e.Message, @"Path: ([^|]+)");
            if (pathMatch.Success)
                path = pathMatch.Groups[1].Value.Trim();
            
            Console.WriteLine($"Error at line {lineNumber}, position {position}, path {path}");
            
            // Display the problematic line
            string[] lines = jsonWithError.Split('
');
            if (lineNumber > 0 && lineNumber <= lines.Length)
            {
                string errorLine = lines[lineNumber - 1];
                Console.WriteLine("\nContext:");
                Console.WriteLine(errorLine);
                
                // Create pointer to error position
                string pointer = new string(' ', position) + "^";
                Console.WriteLine(pointer);
            }
        }
    }
}

C# Feature Note:

Unlike most other languages, System.Text.Json in .NET offers the AllowTrailingCommas option, which can be set to true to make the parser more lenient about trailing commas in objects and arrays.

PHP

PHP offers simple but effective JSON parsing with function-based error handling.

Parsing Mechanism

  • Uses json_decode() function for parsing
  • Returns null on parsing failure rather than throwing exceptions
  • Error details can be retrieved with json_last_error() and json_last_error_msg()
  • Error messages tend to be less descriptive than other languages

PHP Example:

<?php
// Basic error handling in PHP
$jsonString = '{"name": "Michael", "age": 42,}'; // Invalid JSON - trailing comma

$data = json_decode($jsonString);
if ($data === null && json_last_error() !== JSON_ERROR_NONE) {
    echo "Error: " . json_last_error_msg() . "\n";
    // Output: "Error: Syntax error"
}

// Enhanced error handling with context
function parseJsonWithContext($jsonString) {
    $result = json_decode($jsonString);
    if ($result !== null || json_last_error() === JSON_ERROR_NONE) {
        return ['data' => $result, 'error' => null];
    }
    
    $error = json_last_error_msg();
    
    // PHP's error messages don't include position information
    // Let's do some heuristic-based context extraction
    
    // For trailing commas, look for patterns like ",}"
    if (preg_match('/,\s*[\}\]]/', $jsonString, $matches, PREG_OFFSET_CAPTURE)) {
        $pos = $matches[0][1];
        $excerpt = substr($jsonString, max(0, $pos - 20), 40);
        $error .= "\nPossible trailing comma near: " . $excerpt;
    }
    
    // For unquoted keys or values
    if (preg_match('/[{,]\s*([^"\s][^:]*):/', $jsonString, $matches)) {
        $error .= "\nPossible unquoted property name: " . $matches[1];
    }
    
    return ['data' => null, 'error' => $error];
}

$result = parseJsonWithContext($jsonString);
if ($result['error']) {
    echo $result['error'] . "\n";
}
?>

Common PHP JSON Errors

Error ConstantMessageCommon Cause
JSON_ERROR_SYNTAXSyntax errorMost syntax errors (unhelpfully generic)
JSON_ERROR_UTF8Malformed UTF-8 charactersEncoding issues or invalid characters
JSON_ERROR_DEPTHMaximum stack depth exceededNested structures exceeding limits

Ruby

Ruby offers concise but informative JSON parsing errors.

Parsing Mechanism

  • Uses the json gem (part of standard library since Ruby 1.9)
  • Parsing is done with JSON.parse()
  • Raises JSON::ParserError with line, column, and token information
  • Error messages are concise but helpful

Ruby Example:

require 'json'

# Basic error handling
begin
  data = JSON.parse('{"name": "Ruby", "version": 3.1,}')  # Invalid JSON - trailing comma
rescue JSON::ParserError => e
  puts "Error: #{e.message}"
  # Output: "Error: unexpected token at '{"name": "Ruby", "version": 3.1,}'"
end

# Enhanced error visualization
def parse_with_context(json_str)
  begin
    JSON.parse(json_str)
  rescue JSON::ParserError => e
    # Extract error location from message if available
    # Ruby's error messages don't always include position details
    pos_match = e.message.match(/at '(.*)'$/)
    error_context = pos_match ? pos_match[1] : ""
    
    puts "JSON Parse Error: #{e.message}"
    
    # Try to identify the problematic location
    if json_str.include?(error_context)
      position = json_str.index(error_context)
      before = json_str[0...position].split("\n")
      line_num = before.length
      column = before.empty? ? 0 : before.last.length
      
      puts "Approximate location: Line #{line_num}, Column #{column}"
      
      # Show a few lines of context
      lines = json_str.split("\n")
      start_line = [0, line_num - 3].max
      end_line = [lines.length - 1, line_num + 2].min
      
      puts "\nContext:"
      (start_line..end_line).each do |i|
        line_marker = i + 1 == line_num ? ">" : " "
        puts "#{line_marker} #{i + 1}: #{lines[i]}"
      end
    end
    
    return nil
  end
end

parse_with_context('{"name": "Ruby", "version": 3.1,}')

Go

Go provides detailed error information with a focus on simplicity.

Parsing Mechanism

  • Uses the standard library's encoding/json package
  • Primary method is json.Unmarshal()
  • Returns errors with detailed messages including line/column information
  • Error types include *json.SyntaxError and *json.UnmarshalTypeError

Go Example:

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    jsonString := `{
        "name": "Go",
        "version": 1.18,
    }`  // Invalid JSON - trailing comma
    
    var data map[string]interface{}
    err := json.Unmarshal([]byte(jsonString), &data)
    
    if err != nil {
        fmt.Printf("Error: %v\n", err)
        
        // Check for specific error types
        if syntaxErr, ok := err.(*json.SyntaxError); ok {
            // Get the approximate line/column
            line, col := findLineCol(jsonString, int(syntaxErr.Offset))
            fmt.Printf("Syntax error at line %d, column %d\n", line, col)
            
            // Print the problematic line
            printErrorContext(jsonString, line)
        }
    } else {
        fmt.Println("Parsed successfully:", data)
    }
}

// Helper to find line and column from byte offset
func findLineCol(input string, offset int) (line, col int) {
    line = 1
    col = 1
    
    for i := 0; i < offset && i < len(input); i++ {
        if input[i] == '\n' {
            line++
            col = 1
        } else {
            col++
        }
    }
    
    return line, col
}

// Helper to print the context of the error
func printErrorContext(input string, errorLine int) {
    lines := strings.Split(input, "\n")
    if errorLine > 0 && errorLine <= len(lines) {
        startLine := max(0, errorLine-2)
        endLine := min(len(lines), errorLine+2)
        
        fmt.Println("Error context:")
        for i := startLine; i < endLine; i++ {
            prefix := "  "
            if i+1 == errorLine {
                prefix = "> "
            }
            fmt.Printf("%s%d: %s\n", prefix, i+1, lines[i])
        }
    }
}

Cross-Language Comparison

Error Information Richness

LanguagePosition InfoError DetailContext Info
JavaScriptCharacter position onlyMinimalNone
PythonLine, column, positionGoodNone, but error class is specific
Java (Jackson)Line, column, positionExcellentDetailed token expectations
C# (.NET)Line, position, pathExcellentJSON path to error
PHPNonePoorError constant only
RubyPartial (in message)ModerateProblematic token
GoByte offsetGoodSpecific error types

Common Error Patterns Across Languages

  • Similar error detection - Most languages catch the same core syntax errors
  • Position reporting variation - Some give character-level precision, others only line numbers
  • Error message clarity - Ranges from cryptic (PHP) to very descriptive (Java/C#)
  • Context provision - Most require custom code to show the problematic JSON context

Best Practices for Cross-Language JSON

1. Validate Before Sending

Always validate JSON before transmitting it to other systems, especially if those systems use different programming languages:

  • Use a JSON validator in your primary language
  • Consider a schema validation system like JSON Schema
  • Add integration tests that verify JSON compatibility

2. Enhance Error Reporting

Implement better error handling in your application:

  • Create wrapper functions that provide consistent, detailed error messages
  • Include visual context (the problematic line, pointer to error position)
  • For languages with poor position reporting (like PHP), implement heuristics to locate errors

3. Use Language-Appropriate Features

Take advantage of language-specific features:

  • JavaScript: Consider libraries like json5 or jju for more detailed errors
  • Python: Use the JSONDecodeError exception directly for detailed position information
  • Java: Choose Jackson for better error reporting than alternatives
  • C#: Enable appropriate JsonSerializerOptions based on your needs

4. Standardize Error Handling Code

Create reusable error handling patterns to use across your projects:

  • Create utility functions for parsing with enhanced error reporting
  • Implement language-specific wrappers with consistent error formats
  • Consider building or using middleware for web APIs that standardizes JSON error handling

Conclusion

Understanding how different programming languages handle JSON parsing errors is essential when debugging cross-platform applications or building systems that communicate via JSON.

Each language has its own approach to error reporting, from JavaScript's minimal position information to C#'s and Java's detailed error context. By enhancing the default error handling with custom visualizations and context information, you can create a more consistent debugging experience regardless of the language you're working with.

Remember that prevention is better than debugging — validate JSON at creation time, use schema validation where appropriate, and implement thorough testing to catch JSON issues before they reach production.

Need help with your JSON?

Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool