yiisoft/yii2 · error · yii\base\InvalidArgumentException
Exclude/include pattern must be a string.
Error message
Exclude/include pattern must be a string.
What it means
parseExcludePattern() is the single funnel that turns a glob string into the internal ['pattern', 'flags', 'firstWildcard'] structure, and it starts with a defensive type assertion: anything that is not a PHP string throws InvalidArgumentException. Note that both public call paths (normalizeOptions() and lastExcludeMatchingFromList()) guard the call with is_string(), so through the normal API a non-string pattern usually surfaces as the sibling error 262 instead; hitting 263 means a custom subclass or patched helper invoked the parser directly with a scalar/object.
Source
Thrown at framework/helpers/BaseFileHelper.php:871
if (self::matchPathname($path, $basePath, $exclude['pattern'], $exclude['firstWildcard'], $exclude['flags'])) {
return $exclude;
}
}
return null;
}
/**
* Processes the pattern, stripping special characters like / and ! from the beginning and settings flags instead.
* @param string $pattern
* @param bool $caseSensitive
* @return array with keys: (string) pattern, (int) flags, (int|bool) firstWildcard
* @throws InvalidArgumentException
*/
private static function parseExcludePattern($pattern, $caseSensitive)
{
if (!is_string($pattern)) {
throw new InvalidArgumentException('Exclude/include pattern must be a string.');
}
$result = [
'pattern' => $pattern,
'flags' => 0,
'firstWildcard' => false,
];
if (!$caseSensitive) {
$result['flags'] |= self::PATTERN_CASE_INSENSITIVE;
}
if (empty($pattern)) {
return $result;
}
if (strncmp($pattern, '!', 1) === 0) {
$result['flags'] |= self::PATTERN_NEGATIVE;View on GitHub (pinned to 66f00d18a2)
Solutions
- Make every entry of 'only'/'except' a plain string glob in config and call sites.
- If subclassing, keep the is_string() guard before any pattern parsing.
- Sanitize pattern arrays before passing them: array_filter($patterns, 'is_string') or map non-strings to their string form.
- Add a unit assertion over config-driven pattern lists so type drift is caught in CI.
Example fix
// before $options = ['except' => [0, '*.log', new \stdClass()]]; $files = \yii\helpers\FileHelper::findFiles($dir, $options); // after $options = ['except' => ['*.log']]; $files = \yii\helpers\FileHelper::findFiles($dir, $options);
Defensive patterns
Strategy: type-guard
Validate before calling
// Keep pattern lists string-only before any FileHelper call $options['except'] = array_values(array_filter($options['except'] ?? [], 'is_string')); $options['only'] = array_values(array_filter($options['only'] ?? [], 'is_string'));
Type guard
/** @param array<int|string, mixed> $patterns @return list<string> */
function stringPatterns(array $patterns): array
{
$out = [];
foreach ($patterns as $p) {
if (is_string($p)) { $out[] = $p; }
elseif (is_scalar($p)) { $out[] = (string) $p; }
// arrays/objects are dropped — they are not valid patterns
}
return $out;
} Prevention
- Declare pattern lists as string[] in docblocks and config schemas.
- If you subclass FileHelper, keep the built-in is_string() guard before pattern parsing.
- Filter external pattern input through a string-only normalizer at the trust boundary.
When it happens
Trigger: A non-string element (int, float, bool, object) in options['except']/options['only'] reaching the parser — typically via a subclass overriding normalizeOptions()/filterPath() without the is_string() guard; test code calling the private method via reflection; code that injects pre-parsed values into the pattern list mixed with raw non-string scalars.
Common situations: Custom FileHelper subclasses that pre-process pattern lists; config-driven pattern lists where a stray integer or null slips in; refactors that bypass the built-in string checks.
Related errors
- If exclude/include pattern is an array it must contain the p
- FileDependency::fileName must be set
- Unable to open directory: $dir
- The dir argument must be a directory: $dir
- Unable to change ownership, "{$path}" is not a file or direc
AI-assisted analysis of yiisoft/yii2@66f00d18a2 (2026-08-17).
Data as JSON: /api/errors/556ba8f11c3baf02.
Report an issue: GitHub.