yiisoft/yii2 · error · InvalidArgumentException
If exclude/include pattern is an array it must contain the p
Error message
If exclude/include pattern is an array it must contain the pattern, flags and firstWildcard keys.
What it means
When FileHelper filters paths (findFiles/findDirectories/copyDirectory/removeDirectory with 'only'/'except' options), each pattern may be a string or an already-parsed array with exactly the keys 'pattern', 'flags' and 'firstWildcard' — the shape produced internally by parseExcludePattern(). lastExcludeMatchingFromList() re-validates that shape on every entry and throws InvalidArgumentException if any of the three keys is missing. Hand-written or truncated pattern arrays are the typical cause.
Source
Thrown at framework/helpers/BaseFileHelper.php:840
* any, determines the fate. Returns the element which
* matched, or null for undecided.
*
* Based on last_exclude_matching_from_list() from dir.c of git 1.8.5.3 sources.
*
* @param string $basePath
* @param string $path
* @param array $excludes list of patterns to match $path against
* @return array|null null or one of $excludes item as an array with keys: 'pattern', 'flags'
* @throws InvalidArgumentException if any of the exclude patterns is not a string or an array with keys: pattern, flags, firstWildcard.
*/
private static function lastExcludeMatchingFromList($basePath, $path, $excludes)
{
foreach (array_reverse($excludes) as $exclude) {
if (is_string($exclude)) {
$exclude = self::parseExcludePattern($exclude, false);
}
if (!isset($exclude['pattern']) || !isset($exclude['flags']) || !isset($exclude['firstWildcard'])) {
throw new InvalidArgumentException('If exclude/include pattern is an array it must contain the pattern, flags and firstWildcard keys.');
}
if ($exclude['flags'] & self::PATTERN_MUSTBEDIR && !is_dir($path)) {
continue;
}
if ($exclude['flags'] & self::PATTERN_NODIR) {
if (self::matchBasename(basename($path), $exclude['pattern'], $exclude['firstWildcard'], $exclude['flags'])) {
return $exclude;
}
continue;
}
if (self::matchPathname($path, $basePath, $exclude['pattern'], $exclude['firstWildcard'], $exclude['flags'])) {
return $exclude;
}
}
return null;View on GitHub (pinned to 66f00d18a2)
Solutions
- Pass plain glob strings ('except' => ['*.log', '/vendor']) and let FileHelper do the parsing — the array form is an internal representation.
- If arrays are unavoidable, include all three keys exactly as parseExcludePattern() returns them: ['pattern' => '*.log', 'flags' => 0, 'firstWildcard' => 1].
- Validate pattern lists before use: every item is a string or an array with isset($p['pattern'], $p['flags'], $p['firstWildcard']).
- Reject or normalize pattern data coming from JSON/YAML config instead of forwarding it unchecked.
Example fix
// before
$options = ['except' => [
['pattern' => '*.log', 'flags' => 0], // missing firstWildcard
]];
$files = \yii\helpers\FileHelper::findFiles($dir, $options);
// after
$options = ['except' => ['*.log']];
$files = \yii\helpers\FileHelper::findFiles($dir, $options); Defensive patterns
Strategy: validation
Validate before calling
/** Every pattern must be a string, or a fully pre-parsed pattern array. */
function validPatterns(array $patterns): bool
{
foreach ($patterns as $p) {
if (is_string($p)) { continue; }
if (is_array($p) && isset($p['pattern'], $p['flags'], $p['firstWildcard'])) { continue; }
return false;
}
return true;
}
if (!validPatterns($options['except'] ?? []) || !validPatterns($options['only'] ?? [])) {
throw new \InvalidArgumentException('Pattern lists may contain strings or fully pre-parsed arrays only.');
}
$files = \yii\helpers\FileHelper::findFiles($dir, $options); Prevention
- Treat 'only'/'except' as plain string glob lists in configuration; the array form is internal.
- Keep config schemas strict: patterns must be strings.
- Unit-test every config-driven pattern list so shape drift fails in CI, not in production.
When it happens
Trigger: 'except' => [['pattern' => '*.log', 'flags' => 0]] with firstWildcard missing; a nested array like ['only' => [['*.txt']]]; non-string, non-array scalars such as 123 or true in the pattern list (isset() on a scalar fails the same check); pre-parsed pattern arrays round-tripped through cache/serialization losing keys.
Common situations: Developers 'optimizing' by pre-parsing glob patterns into arrays but guessing the key set; YAML/JSON config turning pattern lists into nested structures that are forwarded verbatim; patterns sourced from user input or database settings arriving as arrays instead of strings.
Related errors
- Exclude/include pattern must be a string.
- 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/1b4c2e1bc4b84e43.
Report an issue: GitHub.