Error Handling
How WP_Error and is_wp_error() translate to Siren's typed exception system.
Last updated: April 9, 2026
Error Handling
WordPress uses a dual-path error model: some functions return WP_Error objects on failure (which you check with is_wp_error()), while others return false or null. This means every call site needs defensive checks, and the type of error you get is inconsistent across the API.
Siren uses PHP exceptions. When something fails, it throws a typed exception. You catch what you need and let the rest propagate.
// WordPress: check for WP_Error after every operation
$result = wp_insert_post($args);
if (is_wp_error($result)) {
echo $result->get_error_message();
return;
}
// Some functions return false instead of WP_Error
$meta = get_post_meta($post_id, '_key', true);
if ($meta === false) {
// Was it an error, or does the meta just not exist?
} // Siren: catch typed exceptions
use PHPNomad\Datastore\Exceptions\RecordNotFoundException;
use PHPNomad\Datastore\Exceptions\DuplicateEntryException;
try {
$program = $this->programs->getById($id);
} catch (RecordNotFoundException $e) {
// The program does not exist — handle it
}
try {
$this->collaborators->create($data);
} catch (DuplicateEntryException $e) {
// A collaborator with this email already exists
} Exception reference
Siren and PHPNomad use typed exceptions that tell you exactly what went wrong. Here are the most common ones you will encounter in extension development:
| Exception | When thrown |
|---|---|
RecordNotFoundException | getById() with a nonexistent ID, or a query that expects exactly one result finds none |
DuplicateEntryException | Creating a record that violates a uniqueness constraint (e.g., duplicate email) |
RestException | Generic REST error that carries an HTTP status code and message |
ValidationException | Request validation fails, includes field-level error details |
AuthorizationException | Authenticated but insufficient permissions (HTTP 403) |
AuthenticationException | Not authenticated at all (HTTP 401) |
How does this work in REST controllers?
Siren’s REST controllers automatically catch these exceptions and return appropriate HTTP responses. You do not need to manually convert exceptions to REST error responses:
RecordNotFoundExceptionreturns a 404 responseValidationExceptionreturns a 422 response with field-level errorsAuthorizationExceptionreturns a 403 responseAuthenticationExceptionreturns a 401 responseRestExceptionreturns whatever HTTP status code it carries
This means your controller methods can focus on the happy path. Throw an exception when something goes wrong, and the framework handles the REST error formatting.
What should I catch in extension code?
In extension code (listeners, transformers, services), catch the exceptions you can meaningfully handle and let the rest propagate. Common patterns:
// In a transformer: catch RecordNotFoundException when looking up mappings
try {
$transaction = $this->transactions->getById($mappedId);
} catch (RecordNotFoundException $e) {
// No Siren transaction for this order — return null to skip
return null;
}
// In a listener: catch and log, but don't crash the event pipeline
try {
$this->externalService->sync($data);
} catch (\Exception $e) {
$this->logger->logException($e);
// The sync failed, but the rest of the pipeline should continue
}
The transformer pattern is especially important. Transformers return null to skip events, so catching “record not found” and returning null is the standard way to handle cases where the data does not exist.
If you do not catch an exception in a listener, it will propagate up and may prevent subsequent listeners for the same event from executing. When in doubt, catch broadly in listeners and log the exception so you can diagnose issues without breaking the event pipeline.
Where to go next
For how REST controllers auto-catch exceptions and convert them to HTTP responses, see REST API Patterns. For the full REST error response format (including validation error details), see the Resource Reference Introduction.
For the full PHPNomad framework documentation, see PHPNomad.