phalcon/cphalcon · error · Phalcon\Session\Adapter\Exceptions\SavePathUnavailable
The session save path [{path}] is not writable
Error message
The session save path [{path}] is not writable What it means
SavePathUnavailable is thrown by the Session\Adapter\Stream constructor when the resolved save path exists in configuration but PHP's is_writable() check fails. The process running PHP (www-data, apache, cli user) has no write permission on the directory that holds session files.
Source
Thrown at phalcon/Session/Adapter/Stream.zep:98
public function __construct( array options = [])
{
var path;
let this->prefix = this->getArrVal(options, "prefix", ""),
this->options = options;
/**
* Get the save_path from the passed options. If not defined
* get it from php.ini
*/
let path = this->getArrVal(options, "savePath", this->phpIniGet("session.save_path"));
if unlikely true === empty(path) {
throw new InvalidSavePath();
}
if unlikely true !== this->phpIsWritable(path) {
throw new SavePathUnavailable(path);
}
let this->path = this->toDirSeparator(path);
}
public function destroy(string id) -> bool
{
var file;
let file = this->path . this->getPrefixedName(id);
if this->phpFileExists(file) && is_file(file) {
this->phpUnlink(file);
}
return true;
}
View on GitHub (pinned to b7419de9cd)
Solutions
- Fix ownership and mode for the PHP user: chown -R www-data:www-data /var/lib/app/sessions && chmod 770 /var/lib/app/sessions
- Verify from the app user's perspective: sudo -u www-data test -w /var/lib/app/sessions, or php -r 'var_dump(is_writable($dir));'
- Use a directory guaranteed writable for local work, e.g. sys_get_temp_dir()
- Check open_basedir in php.ini / pool config covers the chosen path
Example fix
// before new Stream(['savePath' => '/var/lib/myapp/sessions']); // SavePathUnavailable: not writable // after (dir owned by the FPM user, writable) // shell: chown www-data:www-data /var/lib/myapp/sessions && chmod 770 /var/lib/myapp/sessions new Stream(['savePath' => '/var/lib/myapp/sessions']);
Defensive patterns
Strategy: validation
Validate before calling
$path = $options['savePath'] ?? ini_get('session.save_path');
if (!is_dir($path)) {
@mkdir($path, 0770, true);
}
if (!is_writable($path)) {
throw new RuntimeException("Session save path {$path} is not writable by " . get_current_user());
} Prevention
- Provision the session directory in deployment scripts with correct owner and mode
- After switching PHP SAPI or user, re-run an is_writable() check on the session directory
- Keep open_basedir in sync with the session path in hardened environments
When it happens
Trigger: savePath points to a directory owned by root while PHP-FPM runs as www-data; directory mode 755 with no write for the PHP user; open_basedir excludes the path; SELinux denies writes; the path is a read-only volume in a container.
Common situations: Manually created session directory with wrong ownership; switching from mod_php (user apache) to PHP-FPM (user www-data) without chown-ing the session directory; hardened shared hosting with open_basedir; systemd PrivateTmp hiding the expected /tmp to other services.
Related errors
- The session save path cannot be empty
- {last PHP error message}
- Failed to write router cache temp file: {tmpPath}
- Failed to commit router cache: {path}
- The session has already been started. To change the id, use
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/0982c62dbcfc5dc6.
Report an issue: GitHub.