sebastianbergmann/phpunit · error · ErrorException

E_USER_ERROR was triggered

Error message

E_USER_ERROR was triggered

What it means

PHPUnit installs its own error handler while a test runs. When code executed inside that test calls trigger_error() with E_USER_ERROR severity, the handler emits a Test\ErrorTriggered event and then throws PHPUnit\Runner\ErrorException('E_USER_ERROR was triggered') so the test is marked as errored. Lower severities (notice, warning, deprecation) are only recorded; E_USER_ERROR is the only user-raised level converted into an exception, because PHP treats it as an abort-level error.

Source

Thrown at src/Runner/ErrorHandler.php:310

                    $ignoredByBaseline,
                    $ignoredByTest,
                    $this->deprecationIgnoredByFilter($errorString, $errorFile, $errorLine, $trigger),
                    $trigger,
                    $this->stackTrace($errorFile, $errorLine),
                );

                break;

            case E_USER_ERROR:
                Event\Facade::emitter()->testTriggeredError(
                    $test,
                    $errorString,
                    $errorFile,
                    $errorLine,
                    $suppressed,
                );

                throw new ErrorException('E_USER_ERROR was triggered');

                /**
                 * No other error type that can be handled by a user-defined
                 * error handler is raised by PHP 8.
                 */
                // @codeCoverageIgnoreStart
            default:
                return $handledByPreviousErrorHandler;
                // @codeCoverageIgnoreEnd
        }

        return $handledByPreviousErrorHandler;
    }

    public function handleNonTestCaseIssue(int $errorNumber, string $errorString, string $errorFile, int $errorLine): true
    {
        /**
         * A previously registered error handler may delegate an error that is being

View on GitHub (pinned to f123cdb2a2)

Solutions

  1. Fix the code under test to throw an exception instead of calling trigger_error(..., E_USER_ERROR).
  2. If the error is expected in this test, declare it: $this->expectException(\PHPUnit\Runner\ErrorException::class); before the triggering call.
  3. If the call must not abort the test, wrap it in a try/catch for \PHPUnit\Runner\ErrorException inside the test and assert on state afterwards.
  4. Downgrade the severity to E_USER_WARNING or E_USER_DEPRECATED when abort semantics are not required; PHPUnit then records the issue instead of throwing.

Example fix

// before
public function testLegacyAbort(): void
{
    LegacyLogger::fail('disk full'); // calls trigger_error(..., E_USER_ERROR)
    self::assertTrue(true);
}

// after
public function testLegacyAbort(): void
{
    $this->expectException(\PHPUnit\Runner\ErrorException::class);
    LegacyLogger::fail('disk full');
}
Defensive patterns

Strategy: try-catch

Try / catch

// inside a PHPUnit test
try {
    LegacyCode::run(); // may call trigger_error(..., E_USER_ERROR)
    self::assertTrue($expectedState);
} catch (\PHPUnit\Runner\ErrorException $e) {
    // reached only when E_USER_ERROR was raised during the call
    self::assertSame('E_USER_ERROR was triggered', $e->getMessage());
}

Prevention

When it happens

Trigger: Test code, or production code the test invokes, executes trigger_error($message, E_USER_ERROR) (E_USER_ERROR is also the default severity of trigger_error(), so a bare trigger_error('msg') in PHP 8 hits this path). Typical sources: legacy libraries that signal fatal conditions via user errors instead of exceptions, or old hand-rolled assertion/abort helpers.

Common situations: Writing tests around legacy PHP code that used trigger_error(E_USER_ERROR) instead of throwing; a dependency raising E_USER_ERROR deep inside a code path under test; porting old test suites whose helpers abort via user errors.

Related errors


AI-assisted analysis of sebastianbergmann/phpunit@f123cdb2a2 (2026-08-23). Data as JSON: /api/errors/c6764a2f2a8c4816. Report an issue: GitHub.