Preserve Stack Trace

ID

php.preserve_stack_trace

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

Php

Tags

exception-handling, reliability

Description

Reports a throw new SomeException(…​) inside a catch block that does not pass the caught exception to the new exception. The original exception, and the stack trace it carries, is then lost.

Rationale

When an exception is caught and a new one is thrown to add context, the caught exception should be forwarded as the cause. PHP exceptions accept a previous exception as the third constructor argument ($previous); chaining it preserves the full trace, which getPrevious() and log formatters rely on for root-cause analysis. Throwing a fresh exception that ignores the caught one hides where the failure actually originated. A bare rethrow (throw $e;) keeps the chain intact and is therefore fine.

<?php
try {
    $this->load();
} catch (\RuntimeException $e) {
    throw new ServiceException('load failed');         // FLAW — drops $e and its trace
}

try {
    $this->load();
} catch (\RuntimeException $e) {
    throw new ServiceException('load failed', 0, $e);  // OK — forwards $e as the previous exception
}

Remediation

Pass the caught exception as the $previous argument of the new exception (new ServiceException($message, $code, $e)), or simply rethrow the original with throw $e; when no extra context is needed.