How to Fix a PHP Reporting Suppresses AJAX Error

In one of my recent PHP based projects, I stumbled across a surprisingly frustrating issue while working with an AJAX widget. Everything worked perfectly in development until I disabled my PHP error reporting settings. Suddenly, the widget failed, and the browser console threw a JSON.parse error. What followed was a deep dive into error reporting and a discovery I think every PHP developer working with AJAX should know.

Original PHP Logging Code

When starting a new project, I typically configure error logging like this:

error_reporting(E_ERROR);
ini_set('display_errors','On');
ini_set('error_log','/var/tmp/don-errors.log');

Here’s what each line does:

  • error_reporting(E_ERROR); – Report only fatal run-time errors.
  • ini_set('display_errors','On'); – Show errors directly in the browser output.
  • ini_set('error_log','/var/tmp/don-errors.log'); – Send all PHP error logs to a custom file.

With these in place, my AJAX widget worked as expected. But then came the problem…

JSON.parse Fails Without Proper Logging

Once I removed the logging configuration, my widget stopped functioning. In the browser’s console, I encountered:

SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data

This happens when JavaScript attempts to parse a response that isn’t valid JSON. For example, if the PHP backend outputs a warning or notice before the actual JSON response, like:

<br />
<b>Notice</b>: Undefined index: po_id in /ajax-handler.php on line 12
{"status":"success","data":{...}}

The browser sees the HTML warning as the start of the response. So, JSON.parse() fails immediately because it expects JSON, not HTML.

Why This Happen

In PHP, if you don’t properly suppress or redirect error output, notices and warnings get included in the actual HTTP response. This breaks the structure of JSON responses that frontend JavaScript is expecting. Instead of a clean:

{"status":"success","data":{...}}

You might end up with:

Notice: Undefined index: po_id in /ajax-handler.php on line 12
{"status":"success","data":{...}}

That tiny warning is all it takes for the entire AJAX call to fail.

Improve PHP Logging for Development

To fix this, I adjusted my logging settings to avoid outputting errors to the browser while still capturing them in a log:

// Recommended development logging
ini_set('display_errors', 'Off'); // Prevent outputting to browser
ini_set('log_errors', 'On'); // Log to file instead
ini_set('error_log', '/var/tmp/don-errors.log'); // Custom log path
error_reporting(E_ALL); // Capture all errors, warnings, notices

By turning off display_errors, I ensured that the output stays clean for JSON responses. Errors now go silently to the log file, where I can review them without breaking AJAX.

Robust AJAX Endpoint

Here’s a simplified version of what my AJAX endpoint looks like now:

<?php
ini_set('display_errors', 'Off');
ini_set('log_errors', 'On');
ini_set('error_log', '/var/tmp/don-errors.log');
error_reporting(E_ALL);

header('Content-Type: application/json');

// Simulated response
$data = [
'status' => 'success',
'data' => [
'message' => 'Data loaded successfully'
]
];

// Uncomment below line to simulate a warning
// trigger_error("Simulated warning!", E_USER_WARNING);

echo json_encode($data);

Now, even if something goes wrong, the output remains valid JSON meaning no JSON.parse issues on the frontend.

Additional Functionalities for Practice

To make my project more robust and educational, I added a few enhancements:

Return Error as JSON

Instead of breaking, return structured error data:

function send_json_error($message) {
echo json_encode([
'status' => 'error',
'message' => $message
]);
exit;
}

Client Side Error Handling with Fallback

Sometimes, we can’t guarantee clean server output. So in JavaScript:

fetch('/ajax-handler.php')
.then(res => res.text())
.then(data => {
try {
const json = JSON.parse(data);
console.log(json);
} catch (e) {
console.error("Invalid JSON response:", data);
}
});

This way, the user doesn’t just see a broken interface.

Server Side Debug Toggle

For a more flexible setup, I added a flag to switch between dev and production modes:

define('DEBUG_MODE', true);

if (DEBUG_MODE) {
ini_set('display_errors', 'Off');
ini_set('log_errors', 'On');
error_reporting(E_ALL);
}

I can easily turn this off when deploying the project live.

Final Thought

This issue reminded me of the hidden complexity in combining server-side PHP with frontend JavaScript. One unnoticed warning in PHP can derail an entire AJAX process if error reporting isn’t handled carefully. By redirecting errors away from the browser and into log files, I was able to maintain clean, parseable JSON responses making the frontend happy and the user experience seamless.

Related blog posts