Problem/Motivation

When running Drupal on multi-container infrastructure (e.g. AWS ECS, Kubernetes), the DropzoneJS Media Library upload silently fails because the module splits the upload into two separate HTTP requests that may hit different containers:

  1. First request (POST /dropzonejs/upload): The file is uploaded and written to tmp_upload_scheme://filename.txt on Container A's local filesystem.
  2. Second request (POST /media-library): The form is submitted and DropzoneJs::valueCallback() calls file_exists() on the temp file — but this request may land on Container B, where the file doesn't exist.

When file_exists() returns false, the file is silently skipped, no media entity is created, and the Media Library re-renders the upload form without any error message. To the user, the upload progress indicator appears briefly then disappears.

The tmp_upload_scheme setting allows changing the scheme to a shared stream wrapper (e.g. s3), but UploadHandler::handleUpload() constructs the path as $scheme . '://' . $filename with no configurable subdirectory. This means temp files are written to the root of the remote storage with no way to namespace or clean them up.

Core's Media Library file upload widget does not have this problem because it handles the upload and form processing in a single request.

Steps to reproduce

  1. Deploy Drupal with the DropzoneJS module on multi-container infrastructure (e.g. AWS ECS with multiple tasks behind a load balancer) where temporary:// maps to each container's local filesystem.
  2. Create a content type or block with a Media reference field using the Media Library widget.
  3. Edit a node/block and open the Media Library to upload a file.
  4. Select a file — the upload progress indicator appears briefly then disappears. No media entity is created. No error is displayed.
  5. Check the watchdog log — no errors are recorded.
  6. Setting tmp_upload_scheme to a shared stream wrapper (e.g. s3) resolves the upload failure, but files are written to the root of the bucket.

Proposed resolution

Add a tmp_upload_path configuration option (e.g. defaulting to dropzonejs-tmp) so that UploadHandler::handleUpload() constructs the temp path as:

$scheme . '://' . $tmp_path . '/' . $filename

This allows sites on multi-container infrastructure to use a shared remote stream wrapper while keeping temp files namespaced in a subdirectory that can have lifecycle/cleanup policies applied.

Additionally, consider logging a warning or setting a form error when file_exists() returns false in DropzoneJs::valueCallback(), rather than silently skipping the file.

Remaining tasks

  • Add tmp_upload_path config option with schema and settings form entry.
  • Update UploadHandler::handleUpload() to use the configured subdirectory.
  • Update DropzoneJs::valueCallback() to use the same subdirectory when resolving temp file paths.
  • Add error logging/user feedback when temp files cannot be found.
  • Document the multi-container setup requirements.

User interface changes

New "Temporary upload path" field on the DropzoneJS settings form (/admin/config/media/dropzonejs).

API changes

New tmp_upload_path key in dropzonejs.settings config.

Data model changes

None.

Comments

jaydee1818 created an issue.