symfony/http-kernel · error · InvalidArgumentException
The profiler token " " is invalid: only letters, digits…
Error message
The profiler token "%s" is invalid: only letters, digits, dashes and underscores are allowed.
What it means
FileProfilerStorage::getFilename() validates that a profile token can safely be used as a file name and throws InvalidArgumentException for anything outside letters, digits, dashes and underscores. This prevents path traversal and malformed paths, since tokens are embedded directly into directory and file names.
Solutions
- Validate the token before calling the storage: use FileProfilerStorage::isValidToken($token) or check it against /^[A-Za-z0-9_-]+$/.
- If loading from user input, reject invalid values with a 400 response instead of passing them to the storage.
- Fix custom token generation to emit only alphanumerics plus '-' and '_' (e.g. the substr(bin2hex(random_bytes(...))) pattern used by Profiler).
- Handle empty tokens explicitly before calling doRead().
Example fix
// before
$profile = $storage->read($_GET['token']); // may contain '/', ':' etc.
// after
$token = $_GET['token'];
if (!FileProfilerStorage::isValidToken($token)) {
throw new \InvalidArgumentException('Invalid profiler token.');
}
$profile = $storage->read($token); Defensive patterns
Strategy: validation
Validate before calling
function isSafeProfilerToken(string $token): bool {
return preg_match('/^[A-Za-z0-9_-]{1,64}$/', $token) === 1;
}
// call before read()/write(); or use FileProfilerStorage::isValidToken($token) Type guard
function validToken(?string $token): ?string {
return ($token !== null && preg_match('/^[A-Za-z0-9_-]+$/', $token) === 1) ? $token : null;
} Try / catch
try {
$profile = $storage->read($token);
} catch (\InvalidArgumentException $e) {
$profile = null; // treat as bad request
http_response_code(400);
} Prevention
- Never pass raw user input as a profiler token without validating it.
- Use the library's own token generator (Profiler) instead of custom token formats.
- Run isValidToken() in code paths shared between storage backends.
- Treat profiler token lookups as untrusted input to guard against path traversal.
When it happens
Trigger: Calling doRead($token) or write($profile) with an invalid token, or removeExpiredProfiles when a stored token contains other characters (e.g. an empty string, slashes, or ':' / '.' from a custom generator).
Common situations: Passing user-supplied token values from query params straight into loadProfile/read, custom token generators emitting characters like ':' or '/', corrupted or empty token values read from another storage backend.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- The validation groups expression or closure must return a…
- Nested expressions in validation groups are not supported…
- Nested closures in validation groups are not supported. Use…
- GroupSequence cannot be used inside an array of validation…
- Validation groups must be strings.
AI-assisted analysis of symfony/http-kernel@aa3a39d728 (2026-09-13).
Data as JSON: /api/errors/4a43dea308491aea.
Report an issue: GitHub.
Appendix: source
Thrown at Profiler/FileProfilerStorage.php:217
fclose($file);
if (1 === random_int(1, 10)) {
$this->removeExpiredProfiles();
}
}
return true;
}
/**
* Gets filename to store data, associated to the token.
*
* @throws \InvalidArgumentException when the token cannot be used as a file name
*/
protected function getFilename(string $token): string
{
if (!self::isValidToken($token)) {
throw new \InvalidArgumentException(\sprintf('The profiler token "%s" is invalid: only letters, digits, dashes and underscores are allowed.', $token));
}
// Uses 4 last characters, because first are mostly the same.
$folderA = substr($token, -2, 2);
$folderB = substr($token, -4, 2);
return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token;
}
/**
* Gets the index filename.
*/
protected function getIndexFilename(): string
{
return $this->folder.'/index.csv';
}
/**View on GitHub (pinned to aa3a39d728)