Transcoding media broken in XF 2.3.10 (404 video)

M@rc

Well-known member
Licensed customer
Affected version
2.3.10
Just uploaded a test video to the XFMG and it doesn't work:

No alert that the video has been transcoded and the video is stuck at 0:00. Check the Console and you'll see it's a 404.

I'm sure you'll see an error in the XF Server Error Log.

I'm thinking it's because of this:

@Chris D any quick patch for this?
 
Video Upload gives me a server error:

Code:
League\Flysystem\FileNotFoundException: File not found at path: video/.../...-....mp4 src/vendor/league/flysystem/src/Filesystem.php:389
Generated by: Unknown account 17.3.2026 at 14:40
Stack trace
#0 src/vendor/league/flysystem/src/Filesystem.php(210): League\Flysystem\Filesystem->assertPresent('video/.../......')
#1 src/vendor/league/flysystem-eventable-filesystem/src/EventableFilesystem.php(430): League\Flysystem\Filesystem->rename('video/.../......', 'xfmg/video/......', Array)
#2 src/vendor/league/flysystem-eventable-filesystem/src/EventableFilesystem.php(395): League\Flysystem\EventableFilesystem\EventableFilesystem->callFilesystemMethod('rename', Array)
#3 src/vendor/league/flysystem-eventable-filesystem/src/EventableFilesystem.php(303): League\Flysystem\EventableFilesystem\EventableFilesystem->delegateMethodCall('rename', Array)
#4 src/vendor/league/flysystem/src/MountManager.php(242): League\Flysystem\EventableFilesystem\EventableFilesystem->rename('video/.../......', 'xfmg/video/......')
#5 src/addons/XFMG/Attachment/Media.php(300): League\Flysystem\MountManager->move('data://video/12...', 'data://xfmg/vid...')
#6 src/addons/XFMG/Service/Media/Creator.php(298): XFMG\Attachment\Media->onAssociation(Object(XFMG\XF\Entity\Attachment), Object(***\***\XFMG\Entity\MediaItem))
#7 src/XF/Service/ValidateAndSavableTrait.php(42): XFMG\Service\Media\Creator->_save()
#8 src/addons/XFMG/Service/Media/Transcoder.php(176): XFMG\Service\Media\Creator->save()
#9 src/XF.php(914): XFMG\Service\Media\Transcoder->XFMG\Service\Media\{closure}()
#10 src/addons/XFMG/Service/Media/Transcoder.php(150): XF::asVisitor(Object(***\***\XF\Entity\User), Object(Closure))
#11 src/addons/XFMG/Ffmpeg/transcoder.php(55): XFMG\Service\Media\Transcoder->finalizeTranscode('/home/web/...')
#12 {main}
Request state
array(1) {
  ["cli"] => string(62) "/home/web/src/addons/XFMG/Ffmpeg/transcoder.php 26"
}
 
Commenting out line 145 in Transcoder.php fixes the issue for me:

Code:
● Update(src/addons/XFMG/Service/Media/Transcoder.php)
  ⎿  User rejected update to src/addons/XFMG/Service/Media/Transcoder.php                 
      142      $finalPath = $data->getAbstractedDataPath();                                                                                                                                                                           
      143                                                                                                                                                                                                                             
      144      File::copyFileToAbstractedPath($outputFile, $finalPath);                                                                                                                                                               
      145 -    File::deleteFromAbstractedPath($queueData['fileName']);                                                                                                                                                               
      145                                                                                                                                                                                                                             
      146      $tempMedia = $this->em()->findOne('XFMG:MediaTemp', ['attachment_id' => $attachment->attachment_id]);                                                                                                                 
      147      $user = $this->em()->find('XF:User', $queueData['user_id']);

I used claude to help me debug this, which I initially thought was related to the cloudflare R2 addon, which it wasn't - this is the explanation claude code gave me:

Code:
Done. Line 145 is commented out with an explanation of why it must stay disabled.                                                                                                                                                   
                                                                                                                                                                                                                                      
❯ that fixed it, are there any negative consequences to this change? also, is this just an incompatibility between xenforo and the r2 addon or is there a bug I should report to someone?                                             
                                                                                                                                                                                                                                      
● Negative consequences: essentially none.                                                                                                                                                                                           
                                                                                                                                                                                                                                      
  The deleted line's intended purpose was to remove the pre-transcode file from storage after the transcoded version was written to $finalPath. But as we established, $finalPath == $queueData['fileName'] in all cases (not just   
  with R2), so the line was always deleting the file it just wrote — it was never successfully cleaning up an "old" file. The actual cleanup of the source path is handled correctly by the move() in onAssociation, which does a     
  copy-then-delete as part of relocating the file to data://xfmg/video/.... So nothing is orphaned.                                                                                                                                   
                                                                                                                                                                                                                                      
  The one theoretical edge case: if Creator::save() throws before onAssociation runs, the transcoded file would sit indefinitely at internal-data://attachments/.... But XF's attachment cleanup job already handles unassociated     
  attachments, so that's covered.
                                                                                                                                                                                                                                      
  ---             
  Who owns the bug: XFMG, and you should report it to XenForo.
                                                                                                                                                                                                                                      
  The R2 addon is innocent here. This is a regression in XFMG's Transcoder.php caused by XenForo's own XF 2.3 RC5 change (2030055-230rc5.php), which introduced file_key as a separate field and switched getAbstractedDataPath() to
  use it instead of file_hash. Before that change, updating file_hash in finalizeTranscode actually changed the path, making $finalPath ≠ $queueData['fileName'] — so the delete was meaningful (it removed the original file at the 
  old hash-based path). When XF decoupled path identity (file_key) from content hash (file_hash), XFMG's transcoder was never updated to account for it.
                                                                                                                                                                                                                                      
  The R2 addon only made it visible: on a local filesystem the bug also exists but the failure is quiet (the background subprocess dies), whereas R2's eventual consistency lets assertPresent's has() pass but then R2::read() throws
   with a full stack trace, which is how you noticed it.
                                                                                                                                                                                                                                      
  Report it to XenForo's bug tracker at xenforo.com — it's an XFMG bug introduced by a core XF change that XFMG didn't adapt to.
 
Back
Top Bottom