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

  1. Verify the path exists with file_exists()/is_readable() before attaching
  2. Use absolute paths (realpath()/ROOT constants) instead of relative
  3. Check that the file-generation step succeeded before building attachments
  4. 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

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


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)