Failed to open stream: No such file or directory en Laravel
Warning: include(): Failed to open stream: No such file or directory. Este error puede aparecer en varias situaciones en Laravel y tiene causas muy distintas según el contexto. Veamos las más comunes y cómo solucionarlas.
Las causas más frecuentes
Antes de ir a las soluciones específicas, las causas más habituales de este error son:
- Storage link no creado: Los archivos en
storage/app/publicno son accesibles públicamente sin el symlink - Paths incorrectos: Usar rutas relativas o construirlas manualmente de forma incorrecta
- Caché de configuración desactualizada: El path está cacheado con un valor viejo
- Autoloader de Composer desactualizado: Composer no conoce una clase nueva
- Permisos de archivo: El servidor web no puede leer el archivo (aunque este da un error diferente)
Error en Storage: el symlink faltante
El escenario más común es intentar acceder a archivos subidos por usuarios:
// En la migración: los archivos se guardan en storage/app/public/
Storage::disk('public')->put('avatars/user-1.jpg', $fileContents);
// Para acceder públicamente necesitas el symlink:
// public/storage → storage/app/public
Si el symlink public/storage no existe, los archivos no son accesibles desde el navegador:
# Crear el symlink
php artisan storage:link
# Verificar que existe
ls -la public/storage
# Debe mostrar: public/storage -> ../storage/app/public
En producción, si tu despliegue no ejecuta php artisan storage:link, los archivos no serán accesibles. Añádelo a tu script de despliegue.
Diferencia entre storage_path(), public_path() y base_path()
Usar el helper incorrecto es otra causa frecuente:
// base_path(): raíz del proyecto
// /var/www/html/tu-proyecto/
$path = base_path('archivo.txt');
// storage_path(): directorio storage/
// /var/www/html/tu-proyecto/storage/archivo.txt
$path = storage_path('app/public/avatars/user-1.jpg');
// public_path(): directorio public/
// /var/www/html/tu-proyecto/public/archivo.txt
$path = public_path('images/logo.png');
// resource_path(): directorio resources/
// /var/www/html/tu-proyecto/resources/views/welcome.blade.php
$path = resource_path('views/welcome.blade.php');
// MAL: Construir el path manualmente
$file = __DIR__ . '/../../storage/app/public/' . $filename; // Frágil
// BIEN: Usar los helpers de Laravel
$file = Storage::disk('public')->path($filename);
// O para verificar si existe antes de leer:
if (Storage::disk('public')->exists($filename)) {
$contents = Storage::disk('public')->get($filename);
} else {
// Manejar el caso de archivo no encontrado
}
La diferencia entre Storage facade y paths directos
// Usando Storage facade (recomendado)
use Illuminate\Support\Facades\Storage;
// Guardar archivo
Storage::put('archivo.txt', 'contenido');
Storage::disk('public')->put('imagen.jpg', $imageData);
// Leer archivo
$content = Storage::get('archivo.txt');
// Verificar existencia
if (Storage::exists('archivo.txt')) {
// ...
}
// Obtener el path absoluto (para funciones PHP nativas que lo necesitan)
$absolutePath = Storage::path('archivo.txt');
// /var/www/html/tu-proyecto/storage/app/archivo.txt
// URL pública (requiere symlink para el disco 'public')
$url = Storage::disk('public')->url('imagen.jpg');
// https://tu-app.com/storage/imagen.jpg
// Usando path directo (cuando necesitas funciones PHP nativas)
$path = storage_path('app/private/report.pdf');
if (file_exists($path)) {
return response()->download($path);
} else {
abort(404, 'Archivo no encontrado');
}
Caché de configuración desactualizada
Cuando haces php artisan config:cache, Laravel cachea todas las configuraciones. Si cambias un path en .env o en config/filesystems.php, el caché sigue usando el valor anterior:
# El error puede aparecer porque el path está cacheado con un valor viejo
# Limpiar y regenerar el caché de configuración
php artisan config:clear
php artisan config:cache # Para volver a cachear en producción
# Si el problema persiste, limpiar todo
php artisan optimize:clear
En desarrollo, es mejor no usar caché de configuración:
# En desarrollo, solo limpiar sin volver a cachear
php artisan config:clear
php artisan route:clear
php artisan view:clear
Error en autoloader de Composer
Si el error menciona un archivo PHP (no de datos), puede ser el autoloader:
# El autoloader no conoce una clase nueva o movida
Failed to open stream: No such file or directory in /vendor/composer/autoload_classmap.php
# Regenerar el autoloader
composer dump-autoload
# En producción, con optimización
composer dump-autoload --optimize
Debuggear paths antes de usarlos
Cuando no estás seguro de un path, añade temporalmente un log o una verificación:
public function downloadReport(Report $report)
{
$filename = "reports/{$report->id}.pdf";
// Debug: ver el path real
\Log::debug('Intentando acceder a: ' . Storage::path($filename));
\Log::debug('Existe: ' . (Storage::exists($filename) ? 'SI' : 'NO'));
if (!Storage::exists($filename)) {
return response()->json([
'error' => 'Archivo no encontrado'
], 404);
}
return Storage::download($filename, "reporte-{$report->id}.pdf");
}
O en Tinker para explorar:
php artisan tinker
>>> storage_path()
=> "/var/www/html/mi-proyecto/storage"
>>> Storage::disk('public')->exists('avatars/1.jpg')
=> false # El archivo no existe con ese path
>>> Storage::disk('public')->files('avatars')
=> ["avatars/user_1_avatar.jpg"] # El nombre real es diferente
Permisos de directorio
Si el archivo existe pero sigue habiendo error, puede ser un problema de permisos:
# Ver permisos del directorio storage
ls -la storage/
# Laravel necesita que el servidor web pueda escribir en storage y bootstrap/cache
chmod -R 775 storage bootstrap/cache
chown -R www-data:www-data storage bootstrap/cache # En Ubuntu/Debian
Manejo correcto de archivos no encontrados
Nunca asumas que un archivo existe. Siempre verifica:
public function getUserAvatar(User $user): string
{
$avatarPath = $user->avatar; // Columna con el path guardado
// Verificar con Storage facade
if ($avatarPath && Storage::disk('public')->exists($avatarPath)) {
return Storage::disk('public')->url($avatarPath);
}
// Devolver avatar por defecto
return asset('images/default-avatar.png');
}
Conclusión
El error “Failed to open stream” en Laravel normalmente tiene que ver con el symlink de storage no creado (php artisan storage:link), uso incorrecto de helpers de path, o caché de configuración desactualizada. La regla general es: siempre usa la Storage facade en lugar de paths directos, siempre verifica la existencia antes de leer, y mantén tu caché limpia cuando cambias configuraciones.