file_put_contents(temporary://...): Failes to open stream: "Drupal\Core\StreamWrapper\TemporaryStream::stream_open" call failed

Created on 13 December 2024, 7 months ago

i've moved D11 temp folder to `/tmp/drupal/mysite`.

in 'settings.php',

$settings = [
  ...
  'file_public_path' => 'sites/default/files',
  'file_private_path' => '/srv/drupal/private',
  'file_temp_path' => '/tmp/drupal/mysite',
  ...

confirming,

drush status | grep -E "^Drupal version|^Files"
	Drupal version   : 11.0.9
	Files, Public    : sites/default/files
	Files, Private   : /srv/drupal/private
	Files, Temp      : /tmp/drupal/mysite

perms are

ls -ald \
 /srv/drupal \
 /srv/drupal/private \
 /tmp/drupal \
 /tmp/drupal/mysite

	drwxrwx---  7 wwwrun www 4.0K Dec 13 10:05 /srv/drupal/
	drwxrwx---  2 wwwrun www 4.0K Dec 13 10:13 /srv/drupal/private/
	drwxrwx---  3 wwwrun www   60 Dec 12 22:57 /tmp/drupal/
	drwxrwx---  2 wwwrun www   80 Dec 13 11:12 /tmp/drupal/mysite/

it's writeable

sudo -u wwwrun touch /tmp/drupal/mysite/test.txt
ls -al  /tmp/drupal/mysite/test.txt
	-rw-r--r-- 1 wwwrun www 0 Dec 13 11:12 /tmp/drupal/mysite/test.txt

on site access, https://example.com/, i see

Notice: tempnam(): file created in the system's temporary directory in Drupal\Core\File\FileSystem->tempnam() (line 274 of core/lib/Drupal/Core/File/FileSystem.php).

	Drupal\Core\File\FileSystem->tempnam() (Line: 484)
	Drupal\Core\File\FileSystem->saveData() (Line: 56)
	Drupal\Core\Asset\AssetDumper->dumpToUri() (Line: 205)
	Drupal\system\Controller\AssetControllerBase->deliver()
	call_user_func_array() (Line: 123)
	Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->{closure:Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber::wrapControllerExecutionInRenderContext():121}() (Line: 593)
	Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 121)
	Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97)
	Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->{closure:Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber::onController():96}() (Line: 183)
	Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 76)
	Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 53)
	Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
	Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28)
	Drupal\Core\StackMiddleware\ContentLength->handle() (Line: 32)
	Drupal\big_pipe\StackMiddleware\ContentLength->handle() (Line: 106)
	Drupal\page_cache\StackMiddleware\PageCache->pass() (Line: 85)
	Drupal\page_cache\StackMiddleware\PageCache->handle() (Line: 48)
	Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
	Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 36)
	Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 51)
	Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 709)
	Drupal\Core\DrupalKernel->handle() (Line: 19)


Warning: file_put_contents(temporary://file11v996hs0u5ceWbEZpg): Failed to open stream: "Drupal\Core\StreamWrapper\TemporaryStream::stream_open" call failed in Drupal\Core\File\FileSystem->saveData() (line 485 of core/lib/Drupal/Core/File/FileSystem.php).

	Drupal\Core\File\FileSystem->saveData() (Line: 56)
	Drupal\Core\Asset\AssetDumper->dumpToUri() (Line: 205)
	Drupal\system\Controller\AssetControllerBase->deliver()
	call_user_func_array() (Line: 123)
	Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->{closure:Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber::wrapControllerExecutionInRenderContext():121}() (Line: 593)
	Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 121)
	Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97)
	Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->{closure:Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber::onController():96}() (Line: 183)
	Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 76)
	Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 53)
	Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
	Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28)
	Drupal\Core\StackMiddleware\ContentLength->handle() (Line: 32)
	Drupal\big_pipe\StackMiddleware\ContentLength->handle() (Line: 106)
	Drupal\page_cache\StackMiddleware\PageCache->pass() (Line: 85)
	Drupal\page_cache\StackMiddleware\PageCache->handle() (Line: 48)
	Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
	Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 36)
	Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 51)
	Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 709)
	Drupal\Core\DrupalKernel->handle() (Line: 19)
🐛 Bug report
Status

Active

Version

11.0 🔥

Component

base system

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @pgndrupal
  • It looks like a permissions issue or that the directory is totally unreachable by the web server process. You are in the best position to solve this one. It isn't a bug in Drupal.

    Is there selinux or other advanced ACL or other file access security system running?

  • no se linux. no app armor.

    it's not perms.
    no combination of dir perms (777, 775, 770, etc) of any/all of the path dirs in `/tmp/drupal/mysite` makes any difference -- same error.
    sticky bit on the dir makes no diff, either.

    checking, any other app running as same user/group (wwwrun:www) under same webserver (nginx) -- namely wordpress, symfony/sulu, joomla, own site, etc -- that needs/uses /tmp space, can be pointed at that same dir, `/tmp/drupal/mysysite`, with no issues.

    D11, using that `/tmp/**/*` path, consistenly reports the error as reported.

    BUT ...

    moving /tmp space to any *other* top-dir location -- e.g., /var/lib/wwwrun/tmp ``` works just fine.
    no error reported, atm.

    what's "different" and common here about `/tmp`, is that it's a shared memory mount:

    mount | grep "/tmp"
      tmpfs on /tmp type tmpfs (rw,nosuid,nodev,nr_inodes=1048576,inode64)
    

    it appears that tmpfs makes it unhappy.

    now as to why, dunno yet. afaik, `saveData()` _shouldn't_ have any issues with tmpfs or not.

    looking online for any relevant or related issues/bugs hasn't borne fruit. yet.

  • @cilefen

    > It looks like a permissions issue or that the directory is totally unreachable by the web server process.

    it doesn't look like a permissions issue to me.
    and, the directory is demonstrably reachable -- for read & write -- by the web server process.

    just, atm, not by D11.

  • this is consistently reproducible here across multiple instances -- different hardware, Drupal installs, persons doing the work.

    for us, it's only an issue -- temp space usags on tmpfs -- with Drupal installs.

    we have a working 'fix' -- don't use tmpfs with Drupal.

    if that's considered a 'support request', and functions "as intended", n/p & noted; pls feel free to close this.

  • 🇺🇸United States nyroofing

    To resolve this issue, ensure that the temporary directory is correctly configured in Configuration > Media > File System and that it has the necessary write permissions. Additionally, verify that the server's PHP configuration allows writing to the specified directory.

  • Maybe it is a bug. Add the steps to reproduce it with a common linux distribution to the issue summary and someone will probably have a look.

    Here is the call point with the warning: https://git.drupalcode.org/project/drupal/-/blob/11.x/core/lib/Drupal/Co...

    It's a little difficult to remove Drupal to test this, with, say, a plain PHP script, because setting up the temporary:// stream wrapper involves a few classes. Otherwise, I would suggest trying that.

  • Actually it would be interesting to know if you were to make a PHP file in the web root called test.php with these contents:

    <?php
    if (file_put_contents('/tmp/drupal/mysite/foobar', 'test') === FALSE) {
          throw new \Exception("Temporary file could not be created.");
    }
    

    Then browse to https://example.com/test.php. This would be a basic test that doesn't use a stream wrapper. What happens?

  • 🇮🇳India ramprassad

    This does not seem to be a drupal issue as file_put_contents with the direct path as mentioned in #19 also doesn't work.

  • @cliefen

    > Then browse to https://example.com/test.php. This would be a basic test that doesn't use a stream wrapper. What happens?

    rm -rf /tmp/drupal
    mkdir -p /tmp/drupal/mysite
    find /tmp/drupal -type d -exec chmod 750 {} \; -exec chown wwwrun:www {} \;
    
    cat /srv/my.app/web/test.php
    	<?php
    
    	if (file_put_contents('/tmp/drupal/mysite/foobar.txt', 'test') === FALSE) {
    		throw new \Exception("Temporary file could not be created.");
    	} else {
    		echo "Temp file created";
    	}
    
    sudo -u wwwrun php /srv/my.app/web/test.php
    	Temp file created
    
    tree -Csup /tmp/drupal/
    	[drwxr-x--- wwwrun            60]  /tmp/drupal/
    	└── [drwxr-x--- wwwrun            60]  mysite
    		└── [-rw-r--r-- wwwrun             4]  foobar.txt
    
    cat /tmp/drupal/mysite/foobar.txt
    	test
    
    rm -f /tmp/drupal/mysite/foobar.txt
    
    nav to: https://example.com/test.php
    
    ==> /var/log/nginx/php-fpm-www.log <==
    	[20-Dec-2024 21:43:44 America/New_York] PHP Warning:  file_put_contents(/tmp/drupal/mysite/foobar.txt): Failed to open stream: No such file or directory in /srv/my.app/web/test.php on line 3
    	[20-Dec-2024 21:43:44 America/New_York] PHP Fatal error:  Uncaught Exception: Temporary file could not be created. in /srv/my.app/web/test.php:4
    	Stack trace:
    	#0 {main}
    	thrown in /srv/my.app/web/test.php on line 4
    
  • 🇺🇸United States cmlara

    @pgndrupal Can you check if your deployment is using SystemD PrivateTmp=true?
    https://stackoverflow.com/questions/53700985/why-cant-write-info-into-tm...

    Note for anyone using #8 you MUST mkdir /tmp/drupal/mysite/ (do not do so in the PHP script as that will contaminate the test) first otherwise file_put_contents will always fail.

    Another test for @pgndrupal would be in settings.php to put @mkdir('/tmp/drupal/mysite/');. If the issue goes away that also implies that PHP is running with a private /tmp space.

  • @cmlara

    indeed!

    in `/etc/systemd/system/php-fpm.service`

    i've

    	[Service]
    	PrivateTmp=true
    

    if

    -	PrivateTmp=true
    +	#PrivateTmp=true
    

    then Drupal's happy with the tempfile location in `/tmp/drupal/**/*`!

    `php-fpm.service` does NOT have a specified `User=/Group=`

    but DOES launch as

    ExecStart=/usr/sbin/php-fpm \
     --nodaemonize \
     --pid /run/nginx/php-fpm.pid \
     --fpm-config /usr/local/etc/php8/php-fpm.conf \
     -c /usr/local/etc/php8/php.ini
    

    where

    cat /usr/local/etc/php8/php-fpm.conf
    	...
    	[www]
    	user         = wwwrun
    	group        = www
    	listen       = /run/nginx/php-fpm.sock
    	listen.owner = wwwrun
    	listen.group = www
    	listen.mode  = 0660
    	...
    

    so

    ps aux | grep php-fpm
    	root     35046  0.0  0.0 697120 43896 ?        Ss   22:11   0:00 php-fpm: master process (/usr/local/etc/php8//php-fpm.conf)
    	wwwrun   35054  0.0  0.0 697120 19416 ?        S    22:11   0:00 php-fpm: pool www
    	wwwrun   35055  0.0  0.0 697120 15040 ?        S    22:11   0:00 php-fpm: pool www
    	wwwrun   35056  0.0  0.0 697120 15168 ?        S    22:11   0:00 php-fpm: pool www
    	wwwrun   35057  0.0  0.0 697120 15168 ?        S    22:11   0:00 php-fpm: pool www
    	wwwrun   35058  0.0  0.0 697120 15168 ?        S    22:11   0:00 php-fpm: pool www
    

    if i

    -	#PrivateTmp=true
    +	PrivateTmp=true
    

    and

    eval echo "~wwwrun"
    	/var/lib/wwwrun
    
    edit settings.php`
    	...
    	$settings = [
    		...$settings,
    	-	'file_temp_path' => '/tmp/drupal/mysite',
    	+	'file_temp_path' => '/var/lib/wwwrun/tmp/drupal/mysite',
    		],
    	...
    

    then it also works, despite the 'correct' ownership of `/tmp/drupal/mysite`.

    which sure seems like it's a namespace issue, as a result of that `PrivateTmp=true`.

    reading,

    https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.htm...

    i'm unclear whether i can 'fix' the issue for Drupal, leaving the (some?) `PrivateTmp=` protection in place.

    i need to take a closer look @ `JoinsNamespaceOf=` ...

    i've not had an issue with php-fpm service's `PrivateTmp=true` with any other service using php-fpm.
    i don't know if this is, or isn't, intended behavior in Drupal.

  • 🇺🇸United States cmlara

    i've not had an issue with php-fpm service's `PrivateTmp=true` with any other service using php-fpm.
    i don't know if this is, or isn't, intended behavior in Drupal.

    I believe this is intended behavior, that any path configured for $settings['file_temp_path'] is expected to be present and accessible to Drupal at the time we are bootstrapped. In other words, I believe it is intentional that we will not call mkdir($settings['file_temp_path]).

    Perhaps other systems 'tried to help you' by recursively creating these folders however they would have masked the underlying 'fault' that you are not directly using /tmp and instead going through a systemd provided abstraction layer.

    Since we don't mkdir() the path, and since PHP-FPM gets a 'virtual' /tmp that does not already have this directory fopen() fails as "path does not exist" which is where the errors above come from. In theory the mkdir() suggestion from #12 could exist indefinitely as a solution for you.

  • not clear what the `mkdir` point you're making is ... (pre)creating the dir doesn't appear to help.
    this fails/failed even IF the dir exists -- separately/previously created -- as above in #11

    the solution is to have Drupal write it's "tempfile" to OTHER than non-allowed `/tmp`.
    either to a different mount path, or _somehow_ by pointing Drupal at the systemd-generated namespaced dynamic /tmp path.

    or, of course, turning OFF `PrivateTmp=true`

  • Status changed to Closed: works as designed 15 days ago
  • 🇳🇿New Zealand quietone

    After reading the comments this seems to be resolved, so I am closing this support request.

    As a reminder. the Drupal Core issue queue is not the ideal place for support requests. The 'support request' option is there for filing support issues for contributed modules and themes. There are several support options listed on our Support page , including the Drupal Forums and Drupal Answers.

  • 🇺🇸United States cmlara

    I believe this is actually a duplicate of 🐛 Local stream wrappers break when directory is missing Needs work as its the inherit root cause is that a configured directory for the streamWrapper did not exist and core did not attempt to validate it existed before usage which caused cascading failures that should reasonably have been predicted to occur.

Production build 0.71.5 2024