dnoegel/php-xdg-base-dir · error · RuntimeException

XDG_RUNTIME_DIR was not set

Error message

XDG_RUNTIME_DIR was not set

What it means

This RuntimeException is thrown by DcborgDev\Xdg\Xdg::getRuntimeDir() when the XDG_RUNTIME_DIR environment variable is not set and the $strict argument is true. XDG_RUNTIME_DIR is where per-user runtime files (sockets, locks, pids) should live, and the XDG Base Directory spec requires it to be set by the session/login manager. In non-strict mode the library silently falls back to a temp-directory path instead.

Solutions

  1. Export XDG_RUNTIME_DIR before running PHP (e.g. export XDG_RUNTIME_DIR=/run/user/$(id -u)) or set it via putenv() in the bootstrap.
  2. Call getRuntimeDir(false) to use the library's /tmp fallback instead of throwing.
  3. On systemd services add RuntimeDirectory= or Environment=XDG_RUNTIME_DIR=/run/user/%U to the unit.
  4. In containers/Docker, set the env var explicitly (ENV XDG_RUNTIME_DIR=/tmp/runtime) and create the directory with correct 0700 permissions.

Example fix

// before
$dir = $xdg->getRuntimeDir(true); // throws if XDG_RUNTIME_DIR unset

// after
$dir = $xdg->getRuntimeDir(false); // falls back to sys_get_temp_dir()/...
Defensive patterns

Strategy: fallback

Validate before calling

if (getenv('XDG_RUNTIME_DIR') === false || getenv('XDG_RUNTIME_DIR') === '') {
    putenv('XDG_RUNTIME_DIR=' . sys_get_temp_dir() . '/runtime-' . getmypid());
}
$dir = $xdg->getRuntimeDir(true);

Type guard

function hasXdgRuntimeDir(): bool {
    $v = getenv('XDG_RUNTIME_DIR');
    return is_string($v) && $v !== '';
}

Try / catch

try {
    $dir = $xdg->getRuntimeDir(true);
} catch (\RuntimeException $e) {
    if ($e->getMessage() === 'XDG_RUNTIME_DIR was not set') {
        $dir = sys_get_temp_dir() . '/myapp-runtime';
        if (!is_dir($dir)) { mkdir($dir, 0700, true); }
    } else {
        throw $e;
    }
}

Prevention

When it happens

Trigger: Calling (new \DcborgDev\Xdg\Xdg())->getRuntimeDir(true) (or any call that defaults $strict to true) via getenv('XDG_RUNTIME_DIR') when that env var is unset in the PHP process environment.

Common situations: Running PHP outside a full desktop session (cron jobs, systemd units without RuntimeDirectory, Docker containers, SSH non-login shells, web-server/PHP-FPM processes) where no login manager exports XDG_RUNTIME_DIR; also CLI workers or CI environments that stripped environment variables.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.


AI-assisted analysis of dnoegel/php-xdg-base-dir@12f5b94710 (2026-09-16). Data as JSON: /api/errors/90f3621011146599. Report an issue: GitHub.

Appendix: source

Thrown at src/Xdg.php:93

    /**
     * @return string
     */
    public function getHomeCacheDir()
    {
        $path = getenv('XDG_CACHE_HOME') ?: $this->getHomeDir() . DIRECTORY_SEPARATOR . '.cache';

        return $path;

    }

    public function getRuntimeDir($strict=true)
    {
        if ($runtimeDir = getenv('XDG_RUNTIME_DIR')) {
            return $runtimeDir;
        }

        if ($strict) {
            throw new \RuntimeException('XDG_RUNTIME_DIR was not set');
        }

        $fallback = sys_get_temp_dir() . DIRECTORY_SEPARATOR . self::RUNTIME_DIR_FALLBACK . getenv('USER');

        $create = false;

        if (!is_dir($fallback)) {
            mkdir($fallback, 0700, true);
        }

        $st = lstat($fallback);

        # The fallback must be a directory
        if (!$st['mode'] & self::S_IFDIR) {
            rmdir($fallback);
            $create = true;
        } elseif ($st['uid'] != $this->getUid() ||
            $st['mode'] & (self::S_IRWXG | self::S_IRWXO)

View on GitHub (pinned to 12f5b94710)