Menu

Error Identifier: match.alwaysTrue

← Back to match.*

Every error reported by PHPStan has an error identifier. Here’s a list of all error identifiers. In PHPStan Pro you can see the error identifier next to each error and filter errors by their identifiers.

Code example #

<?php declare(strict_types = 1);

function doFoo(int $i): string
{
	$flag = true;
	return match (true) {
		$flag => 'always',
		$i > 0 => 'positive',
		default => 'other',
	};
}

Why is it reported? #

A match arm comparison always evaluates to true, which means all subsequent arms are unreachable. In the example above, $flag is always true, so the first arm always matches when compared to the match subject true, making the remaining arms dead code.

Exhaustive enum matches with a default arm #

This error is also reported when a match expression covers all enum cases and also has a default arm:

<?php declare(strict_types = 1);

enum Suit
{
	case Hearts;
	case Diamonds;
	case Clubs;
	case Spades;
}

function suitToColor(Suit $suit): string
{
	return match ($suit) {
		Suit::Hearts, Suit::Diamonds => 'red',
		Suit::Clubs => 'black',
		Suit::Spades => 'black', // match.alwaysTrue: always true
		default => throw new \LogicException('Unknown suit'),
	};
}

The Suit::Spades arm is reported because all four enum cases are already covered before the default arm is reached, making the last arm’s comparison always true (only Suit::Spades can reach it). The error tip says: “Remove remaining cases below this one and this error will disappear too.”

PHPStan discourages having a default arm in exhaustive enum matches on purpose. Without the default arm, PHPStan reports match.unhandled when a new case is added to the enum. This forces you to handle every case explicitly, which is much safer. With a default arm present, new enum cases would silently fall through to the default and the mistake could go unnoticed.

How to fix it #

Remove the unreachable arms:

 <?php declare(strict_types = 1);
 
 function doFoo(int $i): string
 {
-	$flag = true;
-	return match (true) {
-		$flag => 'always',
-		$i > 0 => 'positive',
-		default => 'other',
-	};
+	return 'always';
 }

Or fix the logic so the match arm condition can vary:

 <?php declare(strict_types = 1);
 
-function doFoo(int $i): string
+function doFoo(int $i, bool $flag): string
 {
-	$flag = true;
 	return match (true) {
 		$flag => 'flagged',
 		$i > 0 => 'positive',
 		default => 'other',
 	};
 }

For exhaustive enum matches, remove the default arm:

 return match ($suit) {
 	Suit::Hearts, Suit::Diamonds => 'red',
 	Suit::Clubs => 'black',
 	Suit::Spades => 'black',
-	default => throw new \LogicException('Unknown suit'),
 };

This way, when a new case like Suit::Jokers is added to the enum, PHPStan will report match.unhandled, reminding you to handle it.

By default this error is not reported when the always-true condition is the last one before default. This can be changed with the reportAlwaysTrueInLastCondition configuration option.

How to ignore this error #

You can use the identifier match.alwaysTrue to ignore this error using a comment:

// @phpstan-ignore match.alwaysTrue
codeThatProducesTheError();

You can also use only the identifier key to ignore all errors of the same type in your configuration file in the ignoreErrors parameter:

parameters:
	ignoreErrors:
		-
			identifier: match.alwaysTrue

Rules that report this error #

  • PHPStan\Rules\Comparison\MatchExpressionRule [1]
Theme
A
© 2026 PHPStan s.r.o.