Fix PHP Warning: include() Failed to open stream: No such file or directory

beginner๐Ÿ˜ PHP2026-03-26| PHP 7.x / 8.x on Linux (Apache/Nginx), Windows (XAMPP/WAMP), macOS

Error Message

Warning: include(config.php): Failed to open stream: No such file or directory in /var/www/html/index.php on line 3
#php#include#require#file-path#stream

What just happened

You got this warning โ€” and probably a blank page or broken app โ€” because PHP couldn't find the file you told it to include:

Warning: include(config.php): Failed to open stream: No such file or directory in /var/www/html/index.php on line 3

PHP couldn't resolve config.php to any real file on disk. Nine times out of ten, one of three things is wrong: the file doesn't exist at that path, the current working directory isn't what you assumed, or the path itself has a typo or is just incorrect.

Debug process

Step 1: Figure out what path PHP is actually looking for

The warning only shows the argument you passed โ€” not the full resolved path PHP tried to open. Add a quick debug line above the include to see what's really happening:

<?php
echo __DIR__ . '/' . 'config.php' . PHP_EOL;
include('config.php');

Or use realpath() to check whether the file exists at all:

<?php
$path = __DIR__ . '/config.php';
var_dump(file_exists($path), $path);

Run this, look at the output, then compare it against what's actually on disk.

Step 2: Check the current working directory

A relative path like include('config.php') resolves against the current working directory (CWD), not relative to the file containing the include. These are often different. This catches people out when calling a script from another directory, using a framework front controller, or running via CLI.

<?php
echo getcwd(); // Print the current working directory

Expected /var/www/html but got /var/www? There's your problem.

Step 3: Verify the file actually exists

# On Linux/macOS
ls -la /var/www/html/config.php

# Hunt for typos โ€” Linux is case-sensitive
find /var/www/html -name "config*"

On Linux, Config.php and config.php are two different files. Windows is case-insensitive, so a typo that works fine on XAMPP will blow up the moment you push to a Linux server.

Solutions

Fix 1: Use DIR for reliable relative paths (recommended)

This fixes most cases. __DIR__ is a magic constant that resolves to the directory of the current file โ€” not wherever PHP happened to be invoked from.

<?php
// BEFORE (fragile โ€” breaks when CWD changes)
include('config.php');
include('../lib/helpers.php');

// AFTER (reliable โ€” always relative to this file)
include(__DIR__ . '/config.php');
include(__DIR__ . '/../lib/helpers.php');

Switch every bare relative include/require in your project to use __DIR__. That single change eliminates the vast majority of include path bugs.

Fix 2: Use require instead of include for critical files

When config.php is essential โ€” database credentials, app settings, anything your app can't survive without โ€” use require or require_once instead of include.

The key difference: include emits a Warning and keeps running. require throws a Fatal Error and stops immediately. Letting PHP continue silently with a missing config file almost always produces a second, harder-to-trace error 20 lines later.

<?php
// Stops execution immediately if config.php is missing
require __DIR__ . '/config.php';

Fix 3: Check and fix the actual file path

CWD is correct, but the file lives somewhere else? Fix the path:

<?php
// File is at: /var/www/html/includes/config.php
// Your script is at: /var/www/html/index.php

// Wrong
include('config.php');

// Right
include __DIR__ . '/includes/config.php';

Fix 4: The file genuinely doesn't exist โ€” create it

Sometimes the simplest explanation is the right one. Fresh checkouts often exclude config.php via .gitignore. Look for a template:

# Check for an example config
ls /var/www/html/config.php.example
ls /var/www/html/config.example.php

# Copy and fill in your values
cp config.php.example config.php
nano config.php

Fix 5: File permissions (less common, but real)

The file exists but PHP can't open it:

# Check who owns it and what the permissions are
ls -la /var/www/html/config.php

# PHP typically runs as www-data โ€” give it read access
chown www-data:www-data /var/www/html/config.php
chmod 644 /var/www/html/config.php

Here's the sneaky part: PHP reports "No such file or directory" for both missing files and permission-denied errors. If the file definitely exists but the warning persists, permissions are the next thing to check.

Fix 6: include_path issues

Some older codebases rely on PHP's include_path setting (configured in php.ini or via set_include_path()). To check what's currently configured:

<?php
// See current include_path
echo get_include_path();

// Add your directory
set_include_path(get_include_path() . PATH_SEPARATOR . '/var/www/html/includes');
include 'config.php'; // PHP now searches includes/ as well

That said, don't lean on include_path for your own application files โ€” it's brittle. Use explicit __DIR__ paths and reserve include_path for library or autoload setups.

Verification

After applying a fix, confirm it actually worked before removing debug code:

<?php
$file = __DIR__ . '/config.php';
if (!file_exists($file)) {
    die('File not found: ' . $file);
}
if (!is_readable($file)) {
    die('File not readable: ' . $file);
}
require $file;
echo 'Config loaded OK';

Once it prints "Config loaded OK", strip out the debug lines. Then check the PHP error log to confirm the warning is gone:

# Apache
tail -f /var/log/apache2/error.log

# Nginx + PHP-FPM
tail -f /var/log/php8.x-fpm.log

# Or wherever your php.ini points error_log

Quick reference: include vs require

  • include โ€” Warning on failure, execution continues
  • require โ€” Fatal Error on failure, execution stops
  • include_once / require_once โ€” Same behavior, but skips if the file was already included

For config files, database connections, or anything load-bearing: always use require. Reserve include for optional template fragments.

Lessons learned

The underlying confusion is almost always the same: where PHP was invoked from is not the same as where the file containing the include lives. Use __DIR__. Every time. No exceptions.

Write require __DIR__ . '/something.php' instead of require 'something.php' and you'll never see this warning again.

Inheriting a codebase full of bare relative includes? This grep will show you the full scope of the cleanup:

grep -rn "include\|require" /var/www/html --include="*.php" | grep -v "__DIR__" | grep -v "vendor/"

Every line in that output is a potential path bug waiting to happen.

Related Error Notes