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
SyntaxErroron 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 Message | Likely Cause |
|---|---|
Unexpected token { in JSON | Invalid object start, often in an unexpected place |
Unexpected token : in JSON | Missing or invalid property name before a colon |
Unexpected end of JSON input | Incomplete JSON string, often missing closing brackets |
Unexpected token } in JSON | Unexpected closing brace, perhaps due to mismatched brackets |
Unexpected token ' in JSON | Single quotes instead of required double quotes |
Python
Python provides more detailed error information than JavaScript.
Parsing Mechanism
- Uses the
jsonmodule in the standard library - Main function is
json.loads()(for strings) orjson.load()(for files) - Raises
json.JSONDecodeErrorwhich 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
ObjectMapperwith methods likereadValue() - Throws
JsonParseExceptionwith 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.Jsonnamespace - Key method is
JsonSerializer.Deserialize() - Throws
JsonExceptionwith 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
nullon parsing failure rather than throwing exceptions - Error details can be retrieved with
json_last_error()andjson_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 Constant | Message | Common Cause |
|---|---|---|
JSON_ERROR_SYNTAX | Syntax error | Most syntax errors (unhelpfully generic) |
JSON_ERROR_UTF8 | Malformed UTF-8 characters | Encoding issues or invalid characters |
JSON_ERROR_DEPTH | Maximum stack depth exceeded | Nested structures exceeding limits |
Ruby
Ruby offers concise but informative JSON parsing errors.
Parsing Mechanism
- Uses the
jsongem (part of standard library since Ruby 1.9) - Parsing is done with
JSON.parse() - Raises
JSON::ParserErrorwith 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/jsonpackage - Primary method is
json.Unmarshal() - Returns errors with detailed messages including line/column information
- Error types include
*json.SyntaxErrorand*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
| Language | Position Info | Error Detail | Context Info |
|---|---|---|---|
| JavaScript | Character position only | Minimal | None |
| Python | Line, column, position | Good | None, but error class is specific |
| Java (Jackson) | Line, column, position | Excellent | Detailed token expectations |
| C# (.NET) | Line, position, path | Excellent | JSON path to error |
| PHP | None | Poor | Error constant only |
| Ruby | Partial (in message) | Moderate | Problematic token |
| Go | Byte offset | Good | Specific 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
json5orjjufor more detailed errors - Python: Use the
JSONDecodeErrorexception directly for detailed position information - Java: Choose Jackson for better error reporting than alternatives
- C#: Enable appropriate
JsonSerializerOptionsbased 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