cakephp/cakephp · error · InvalidArgumentException
File not found
Error message
File not found: `%s`
What it means
When an attachment's 'file' value is a string path, setAttachments() resolves it with realpath() and checks file_exists(); if the path cannot be resolved or the file does not exist, it throws InvalidArgumentException('File not found: `%s`') with the original path.
Solutions
- Verify the path exists with file_exists()/is_readable() before attaching
- Use absolute paths (realpath()/ROOT constants) instead of relative
- Check that the file-generation step succeeded before building attachments
- Inspect the printed path in the message to catch typos
Example fix
// before
$message->setAttachments([LOGS . 'missing.log']);
// after
$path = LOGS . 'report.log';
if (!is_file($path)) { throw new RuntimeException("Missing attachment: $path"); }
$message->setAttachments([$path]); Defensive patterns
Strategy: validation
Validate before calling
$path = realpath($candidate);
if ($path === false || !is_file($path) || !is_readable($path)) {
throw new \RuntimeException("Attachment file missing/unreadable: $candidate");
}
$message->setAttachments([$path]); Type guard
function attachableFile(mixed $file): ?string {
$p = is_string($file) ? realpath($file) : false;
return ($p !== false && is_file($p) && is_readable($p)) ? $p : null;
} Try / catch
try {
$message->setAttachments($attachments);
} catch (\InvalidArgumentException $e) {
$this->logger->warning('Skipping missing attachment: ' . $e->getMessage());
// send without the missing file
} Prevention
- Use absolute paths (ROOT/LOGS/constants) instead of CWD-relative ones
- Confirm file-generating steps succeeded before emailing
- Check tmp file lifetimes — don't attach already-cleaned temp files
- Verify files exist inside containers/volumes
When it happens
Trigger: Attaching a path that is wrong, deleted, unreadable due to symlinks broken, or relative to a different working directory than expected. Called via addAttachments()/setAttachments().
Common situations: Relative paths resolving differently under CLI vs web SAPI (different CWD); files generated in a previous step that failed; temp files already cleaned up; typo in path; Docker containers missing the file.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- File must be a filepath or UploadedFileInterface instance…
- No file or data specified.
- No filename specified.
- Could not load configuration file
- Could not send email
AI-assisted analysis of cakephp/cakephp@1128eba9b0 (2026-09-12).
Data as JSON: /api/errors/c808ff8f6a1acf5c.
Report an issue: GitHub.
Appendix: source
Thrown at src/Mailer/Message.php:1190
if (!isset($fileInfo['file'])) {
if (!isset($fileInfo['data'])) {
throw new InvalidArgumentException('No file or data specified.');
}
if (is_int($name)) {
throw new InvalidArgumentException('No filename specified.');
}
$fileInfo['data'] = chunk_split(base64_encode($fileInfo['data']), 76, "\r\n");
} elseif ($fileInfo['file'] instanceof UploadedFileInterface) {
$fileInfo['mimetype'] = $fileInfo['file']->getClientMediaType();
if (is_int($name)) {
$name = $fileInfo['file']->getClientFilename();
assert(is_string($name));
}
} elseif (is_string($fileInfo['file'])) {
$fileName = $fileInfo['file'];
$fileInfo['file'] = realpath($fileInfo['file']);
if ($fileInfo['file'] === false || !file_exists($fileInfo['file'])) {
throw new InvalidArgumentException(sprintf('File not found: `%s`', $fileName));
}
if (is_int($name)) {
$name = basename($fileInfo['file']);
}
} else {
throw new InvalidArgumentException(sprintf(
'File must be a filepath or UploadedFileInterface instance. Found `%s` instead.',
gettype($fileInfo['file']),
));
}
if (
!isset($fileInfo['mimetype'])
&& isset($fileInfo['file'])
&& is_string($fileInfo['file'])
&& function_exists('mime_content_type')
) {
$fileInfo['mimetype'] = mime_content_type($fileInfo['file']);
}View on GitHub (pinned to 1128eba9b0)