octobercms/october · error · ApplicationException
File not found
Error message
File not found
What it means
ThemeExport::download($name) only accepts internal tokens matching ^oc[0-9a-z]*$ - the uniqid('oc') names export() generates. A mismatch means the caller passed something other than a fresh export token (a display filename, an edited/truncated value, or an injected path). The regex doubles as a path-traversal guard: dots, slashes, and separators are all rejected.
Source
Thrown at modules/cms/models/ThemeExport.php:152
}
if (strlen($zipPath) && File::isFile($zipPath)) {
File::delete($zipPath);
}
throw $ex;
}
return $zipName;
}
/**
* download
*/
public static function download($name, $outputName = null)
{
if (!preg_match('/^oc[0-9a-z]*$/i', $name)) {
throw new ApplicationException('File not found');
}
$zipPath = temp_path() . '/' . $name;
if (!file_exists($zipPath)) {
throw new ApplicationException('File not found');
}
$headers = Response::download($zipPath, $outputName)->headers->all();
$result = Response::make(File::get($zipPath), 200, $headers);
@File::delete($zipPath);
return $result;
}
}
View on GitHub (pinned to b608633a7e)
Solutions
- Pass the exact string returned by ThemeExport::export() as $name; use the second parameter $outputName for the user-facing filename.
- If the token came from a request, verify it was not truncated or altered (URL-encoding, escaping); regenerate the export rather than massaging the token.
- Treat regex failure as a bad request - do not normalize the input to fit the pattern.
Example fix
// before: display filename passed as the token - fails ^oc[0-9a-z]*$
ThemeExport::download('my-theme-export.zip');
// after: internal token for $name, pretty name for $outputName
$token = ThemeExport::export($theme, $data); // e.g. 'oc64f1a2b3c4d5'
return ThemeExport::download($token, 'my-theme-export.zip'); Defensive patterns
Strategy: validation
Validate before calling
if (!preg_match('/^oc[0-9a-z]*$/i', $name)) {
// reject with 400 before calling ThemeExport::download()
abort(400, 'Invalid export token');
} Type guard
function isValidThemeExportToken(string $name): bool
{
return (bool) preg_match('/^oc[0-9a-z]*$/i', $name);
} Try / catch
try {
return ThemeExport::download($token, 'theme.zip');
} catch (ApplicationException $e) {
abort(404); // bad or tampered token - do not echo the path
} Prevention
- Forward the export() return value untouched to download(); keep user-facing names in $outputName.
- Never round-trip tokens through user-editable fields or URLs that get rewritten.
- Regenerate the export on failure instead of massaging the token to fit the regex.
When it happens
Trigger: Calling download() with a value that fails the regex: ThemeExport::download('my-theme.zip') (dots), a user-modified ?token= URL containing ../ or slashes, or code that passes the $outputName into $name instead of the token returned by export().
Common situations: Controllers persisting or round-tripping download tokens through user-editable state; URL truncation/HTML-escaping mangling the token; attempts to reuse the pretty filename as the token.
Related errors
- cms::lang.cms_object.invalid_file
- Invalid image file name.
- Cannot find the requested row group.
- Inspector container ${$containerHolder.data['inspector-conta
- Cannot switch to container: a container element is not found
AI-assisted analysis of octobercms/october@b608633a7e (2026-08-21).
Data as JSON: /api/errors/5ae9f0e60e5e1d97.
Report an issue: GitHub.