ellite/Wallos · error · Exception
$this->lang('file_open') . $path
Error message
$this->lang('file_open') . $path What it means
encodeFile() throws lang('file_open') plus the path when fileIsAccessible() fails just before reading the attachment during message assembly (attachAll -> encodeFile). This is a re-check at send time — the file became inaccessible after addAttachment() accepted it. Severity STOP_CONTINUE means send() aborts the message but the error may be collected rather than thrown if exceptions are off.
Solutions
- Re-verify the file still exists and is readable immediately before send()
- Keep temporary attachment files alive until after send() returns (use copy() to a durable location)
- Ensure the sending process user retains read permission on the path
- Check $mail->ErrorInfo for the exact path that failed
Example fix
// before
$mail->addAttachment($tmpPath);
// later
$mail->send(); // tmp already deleted
// after
$mail->addAttachment($tmpPath);
if (!is_readable($tmpPath)) { copy($tmpPath, $perm = tempnam(sys_get_temp_dir(), 'att')); $mail->clearAttachments(); $mail->addAttachment($perm); }
$mail->send(); Defensive patterns
Strategy: validation
Validate before calling
foreach ($paths as $p) { if (!is_file($p) || !is_readable($p)) { throw new RuntimeException("Attachment disappeared: $p"); } }
$mail->send(); Type guard
function ensureReadableAtSend(string $p): string { if (!is_file($p) || !is_readable($p)) { throw new RuntimeException("File unreadable at send time: $p"); } return $p; } Try / catch
try { $mail->send(); } catch (PHPMailer\PHPMailer\Exception $e) { if (str_contains($e->getMessage(), 'Could not access file') || str_contains($e->getMessage(), 'file_open')) { error_log('Attachment unreadable at send: ' . $e->getMessage()); } throw $e; } Prevention
- Copy temp attachments to a stable location and delete only after send()
- In queue-based systems, re-verify attachments in the send worker
- Keep attachment lifetime longer than the add-to-send interval
- Monitor $mail->ErrorInfo which contains the offending path
When it happens
Trigger: File exists when addAttachment() is called but is deleted, moved, or made unreadable before send(); also mismatched permissions after a job queue delay between add and send.
Common situations: Temp files (e.g. tmpfile uploads) cleaned up before send(), files removed by cron between validation and transmission, long-running workers holding stale paths.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- $this->lang('file_access') . $path
- $this->lang('encoding') . $encoding
- ( )
- %s: %s
- Invalid address (to/cc/bcc)
AI-assisted analysis of ellite/Wallos@52820e87ca (2026-09-13).
Data as JSON: /api/errors/3b49c38860658935.
Report an issue: GitHub.
Appendix: source
Thrown at libs/PHPMailer/PHPMailer.php:3402
$mime[] = sprintf('--%s--%s', $boundary, static::$LE);
return implode('', $mime);
}
/**
* Encode a file attachment in requested format.
* Returns an empty string on failure.
*
* @param string $path The full path to the file
* @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
*
* @return string
*/
protected function encodeFile($path, $encoding = self::ENCODING_BASE64)
{
try {
if (!static::fileIsAccessible($path)) {
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
}
$file_buffer = file_get_contents($path);
if (false === $file_buffer) {
throw new Exception($this->lang('file_open') . $path, self::STOP_CONTINUE);
}
$file_buffer = $this->encodeString($file_buffer, $encoding);
return $file_buffer;
} catch (Exception $exc) {
$this->setError($exc->getMessage());
$this->edebug($exc->getMessage());
if ($this->exceptions) {
throw $exc;
}
return '';
}
}View on GitHub (pinned to 52820e87ca)