Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Stack Trace Laravel Package

innmind/stack-trace

A lightweight PHP library for working with stack traces: capture them, inspect individual frames, and render readable traces for debugging and error reporting. Framework-agnostic and simple to drop into existing error handlers.

View on GitHub
Deep Wiki
Context7

Getting Started

Install it as a normal Composer dependency, but check the PHP constraint first:

composer require innmind/stack-trace

The 5.1.0 release dropped PHP 8.4 support. That is the single most important fact for onboarding: if your app or CI image runs PHP 8.4, composer require will fail to resolve (or silently keep you on 5.0.0). Confirm before you start:

php -v
composer show innmind/stack-trace --all | grep -i versions

If you are on 8.4 you have two options: stay pinned to 5.0.0, or run this package's consumers on 8.3 in a separate job. Do not assume a future patch will restore 8.4 — the constraint was removed in a minor release, so treat the support matrix as volatile.

Beyond that, the package still sits at 0 stars and 0 dependents, so the repository remains the only source of truth. Your first ten minutes:

  1. Read the README — it is the only documentation you will get.
  2. ls vendor/innmind/stack-trace/src and open every file. The package is small (it only models stack frames), so you can read it end-to-end in one sitting and stop guessing.
  3. Note the exact entry point and the shape of the frame objects (class name, method, file, line, arguments). Everything below assumes you have confirmed those names against src/.
  4. Check composer.json for the PHP constraint (now the interesting part) and the Innmind\Immutable style dependencies the author usually pulls in — those types will leak into your call sites.

First use case: a readable exception trace in your logs. Throwable::getTrace() gives you nested arrays of scalars; this package gives you objects you can traverse, filter, and render. Start by replacing one $e->getTraceAsString() call in your exception handler / report() hook with a structured trace:

try {
    $this->handle($request);
} catch (\Throwable $e) {
    $this->logger->error($e->getMessage(), [
        'trace' => /* structured trace built from $e */,
    ]);

    throw $e;
}

Verify the output against getTraceAsString() for the same exception — if they disagree, you are using the API wrong.

Implementation Patterns

Build the trace once, at the boundary. Construct the trace object in your single exception handler, HTTP middleware, or console error handler. Do not scatter trace construction through domain code; the trace is a presentation/logging concern and domain code should not know about it.

Convert to a plain array for transports. Log aggregators, queue payloads, and JSON APIs cannot carry your objects. Add one adapter that flattens the trace into ['class' => ..., 'function' => ..., 'file' => ..., 'line' => ...] frames. Keep the adapter in your own code, not in a wrapper package — the mapping is three lines and you will want to change it when you add args or vendor flags.

Filter before you store. Traces are noisy. Two filters pay for themselves immediately:

  • drop frames whose file lives under vendor/ (or keep only those, when you are debugging a dependency);
  • collapse consecutive frames from the same vendor package into one entry.

Apply the filter on the way out, not on the way in, so the raw trace stays available for the case where you need it.

Walk the getPrevious() chain. An exception's most useful frame is often in the wrapped exception, not the outer one. Build a list of traces, one per exception in the chain, and render them in order — most libraries that "just show the trace" get this wrong.

Integrate as a PSR-3 processor. If you use Monolog, register a processor that attaches the structured trace to every record with an exception context key. That gives you one integration point instead of touching every catch block. In Laravel, the equivalent is overriding report() in App\Exceptions\Handler (or a reportable callback) so every uncaught exception carries the same shape.

Assert on traces in tests. This is where a structured trace actually earns its keep: a custom exception thrown from a deep call stack becomes assertable — "the trace contains a frame in App\Billing", "no frame references vendor/", "frame count is under N". That is far more robust than string-matching getTraceAsString().

Pin the runtime alongside the version. Given 5.1.0's PHP 8.4 drop, record both in one place — composer.json ("innmind/stack-trace": "5.1.0") and the CI matrix (php: 8.3). If you let composer update float the package while CI floats the PHP image, you will get a resolution failure in the pipeline with no obvious cause.

Keep it out of production responses. The trace exposes absolute paths and (unless zend.exception_ignore_args=1) argument values — potentially passwords and tokens. Use it for logs and dev-only debug pages; never in a user-facing 500 page.

Gotchas and Tips

The 5.1.0 PHP 8.4 drop is a semver smell, not just a constraint. Removing runtime support is a breaking change for anyone on 8.4, yet it shipped as 5.1.0. Consequences for you: ^5.1 no longer means "safe patch upgrades", a future 5.2.0 may re-add or further narrow support, and composer update can change your platform requirements without a major bump. Pin an exact version and upgrade deliberately. Also check whether your other Innmind dependencies (which may still allow 8.4) now conflict — a shared Innmind\Immutable on a stricter constraint is the usual way this bites.

Immutability means you must use return values. Innmind packages are consistently immutable: every method returns a new instance rather than mutating. Code like $trace->filter($f); followed by $trace->frames() will silently do nothing. Assign the result.

Dependency types leak. Expect Innmind\Immutable\Sequence / Set / Maybe in return types rather than plain arrays. If your codebase does not already use Innmind's collections, you will be writing ->toList() / ->match() adapters at every boundary. Budget for that — it is usually the real cost of adopting a single Innmind package.

zend.exception_ignore_args changes what you get. If that ini setting is 1 (the production default in many distributions), frames carry no arguments and any code that reads them will return empty. Do not build features on argument inspection without checking the setting — and prefer keeping it at 1 in production for the security reason above.

Traces are captured at throw time, not at render time. Re-throwing (throw new \RuntimeException('...', 0, $e)) preserves the original trace only through the previous chain. If you build the trace in a handler that constructs a fresh exception, you have already lost the interesting frames.

Serialization is not free. Frames may reference arguments that are objects or closures. If you serialize() or json_encode() the trace object directly, you can hit Serialization of 'Closure' is not allowed or gigantic payloads. Always go through your own array adapter.

Version churn is now demonstrated, not hypothetical. Pre-release churn was the prediction in the previous assessment; 5.1.0 confirms it. Keep the package behind one small internal class of your own (an ExceptionTraceFormatter) so an upstream rename — or another platform-constraint surprise — means editing one file rather than fifty. Read the diff between 5.0.0 and 5.1.0 before upgrading; a release whose only note is "drop PHP support" often carries silent composer.json edits to other constraints too.

Debugging the package itself. When the output looks wrong, compare against $e->getTrace() directly — frame counts often differ by a small offset because the throw site and the getTrace() call site are counted differently. If they never agree, you are probably on the wrong entry point; re-read src/.

Extension points are your own. With no plugin system in a package this small, the intended extension mechanism is composition: write a formatter that takes the trace and returns a string or array, and decorate it for vendor filtering, colouring, or redaction. Do not fork the package for formatting needs.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core