Batch PDF download: 404 error (v5.2.14-C56)


Whenever I try to download multiple PDFs at the same time, I get a 404 error:

This happens when clicking on the link sent by email by IN when asking to batch download files. I tried visiting the /storage folder manually and there is indeed no folder with a long hash like the one in the URL. It looks like the files were actually never generated and thus the link points to a dead-end.

My permissions for the /storage folder are 0755.

Is there anything I need to configure for this to work is is this a bug?


Thanks for reporting this!

@david any thoughts?


The files should be stored in /public/storage/

Depending on how you have configured your APP_URL - you may need to append public into your APP_URL as well.

Thanks for the tip @david!

So I added /public to my app url in .env, then ran artisan optimize. It took a while for the app to rebuild something upon restarting it but it fired up correctly.

I then tried downloading a few PDFs and I first got a TimeoutException. I tried again, and this time the email was successfully sent with the download link - but the new link is still pointing to a random URL with nothing in it.

I also visited /storage: nothing new in there, just the usual app, framework and logs folders:


All in all I don’t know what adding /public to the URL did - it doesn’t seem like breaking anything, but it didn’t fix the batch PDF download either, which seem to not get generated/stored at all when using the batch option (single PDFs can be downloaded with no problem).

FYI my install is pretty basic, just an unzipped in a subdomain folder with default .htaccess config (running on Litespeed Enterprise), both in app root and in /public. IN has no problem writing into storage with the default configuration, if I take laravel.log as an example.

Do you have any other ideas as to what might be not working right?



Sorry @david about my last screenshot, I actually was looking into /storage, not into /public/storage.

public/storage does indeed have the directories it’s supposed to have, at least when it comes to standard invoices, file attachments and logos:

To confirm that IN is properly linked to its storage I just tried adding a document to an expense: everything works fine; I can access it though IN and I can see it in the /public/storage/documents with the default server configuration (no /public in the app url).

That being said, there is no sign of the directory the IN email points to, it seems like it was never created in that form (I also tried checking for hidden files).

So then I tried looking for the file the URL is pointing to, which is in this case

Well, I did find it, it was buried here:


Now the automated email sends me here:


At first glance, both URLs look the same, but they actually differ after the forward slash following the first set of random characters. So:

/public/storage/sAyYOHFwghChDSRWxvKQIKPNXRIRQ9SYrdgto4SGenIHt82gUfbLSkc3ABTTfHwM/ is the common bit between the two URLs and that points to an existing directory.

But then the second part of the email URL
/1evJRh8Du1TZUYIaFb5jnParjQEuQ5FcVj3vH8RL/8zg1xsHFT3ISACy72RJKBct37q4AG1wufYWQ7RzI/invoices/ simply does not exist on my server.

What does exist is /7ve6t7J5b8lzJlJpNSXZEmVMX80bWfpyBGAF08MJ/VOJYlbIpy3a0M75S27NI7BjXmKAhqztwykxYv8Wo/invoices/

So basically I think I found a bug… the batch download command does create a proper zip file containing the appropriate files that were batch selected, but then the email supposedly linking to this zip file is pointing instead to a non existent subfolder, while still having the first and the last part of the URL right.

Thanks for looking into this!


This should be resolved in 5.2.15 please ping me here if you still see an issue.

Hi @david,

I did not try it on v5.2.15 but still have the issue on v5.2.16:


This time the directory that the email link pointed to was existing, but the file was not there! It was not actually anywhere (I tried searching through other directories for it).


I’ve tested this one extensively and cannot recreate this.

My guess is the zip file isn’t being created at all due to either file permissions or perhaps a missing .zip extension?

Thanks for the time you’ve put into this David!

It’s weird, because on the current version (v5.2.16-C56) it’s not being created at all, but on v5.2.14-C56 when I tested it right before creating this thread the zip file was actually created, but the email was not pointing to the right directory, hence the 404 error.

Now, the email is pointing to the correct directory, but the zip doesn’t get created!

laravel.log is empty, there is no error message anywhere as far as I know - my only clue is a link pointing to a nonexistent file. Is there any other way to guess what might be happening here?

My permissions seem to be OK (0755) and the hashed directories under /public/storage are successfully accessed by IN when creating PDFs. Is there anything else to check permission wise?

As for the zip extension, it’s properly installed and running:

Just to be sure, I tried zipping my laravel log file through the cPanel File Manager - it worked:

I also tried looking at my browser console to see if there were errors; I can’t find any. When I click the export button, the following text is printed, but I have no idea what should be there or not:

js_primitives.dart:47 POST:
23:22:23.199 VM6:1 XHR chargement terminé : POST "".
(anonymes) @ VM6:1
k_ @ html_dart2js.dart:9187
duH @ main.foss.dart.js?v=5.2.16:4833
(anonymes) @ main.foss.dart.js?v=5.2.16:132235
(anonymes) @ async_patch.dart:126
$2 @ linked_hash_map.dart:92
$1 @ linked_hash_map.dart:339
vz @ stream_impl.dart:826
$0 @ broadcast_stream_controller.dart:279
a2_ @ future_impl.dart:629
uc @ async_patch.dart:621
$0 @ broadcast_stream_controller.dart:161
e7c @ future_impl.dart:757
ebE @ future_impl.dart:778
$1 @ linked_hash_map.dart:159
ekr @ js_helper.dart:1826
(anonymes) @ js_helper.dart:1858
childList (asynchrone)
$1 @ linked_hash_map.dart:175
dD8 @ future_impl.dart:770
cRO @ zone.dart:1354
tS @ stream_impl.dart:846
a2E @ async_patch.dart:633
mS @ async_patch.dart:615
al @ async_patch.dart:198
h7 @ async_patch.dart:205
aa3 @ object.dart:3360
dqo @ main.foss.dart.js?v=5.2.16:32323
mR @ node.dart:156
u9 @ node.dart:171
oU @ main.foss.dart.js?v=5.2.16:85355
dX @ main.foss.dart.js?v=5.2.16:85356
K5 @ dropdown.dart:1527
a5W @ icon_button.dart:386
eval @ VM1111:3
agd @ main.foss.dart.js?v=5.2.16:87816
jp @ lsq_solver.dart:188
aft @ multitap.dart:262
a3b @ multitap.dart:67
afr @ multidrag.dart:488
tl @ monodrag.dart:260
eval @ VM1374:3
ayJ @ long_press.dart:420
$2 @ long_press.dart:495
N @ iterable.dart:847
a4h @ long_press.dart:464
ajN @ long_press.dart:462
nf @ change_notifier.dart:251
W4 @ change_notifier.dart:249
W4 @ basic.dart:5795
a5S @ linked_list.dart:174
aUX @ change_notifier.dart:196
QZ @ change_notifier.dart:196
aEz @ main.foss.dart.js?v=5.2.16:86944
eval @ VM917:3
aUa @ platform_dispatcher.dart:911
aIx @ main.foss.dart.js?v=5.2.16:63279
eval @ VM886:3
$1 @ platform_dispatcher.dart:379
$1 @ text_editing.dart:1325
$1 @ picture.dart:33
ekr @ js_helper.dart:1826
(anonymes) @ js_helper.dart:1858



I can recreate the issue on my cPanel version of Invoice Ninja.

I think the issue may be the allow_url_fopen may be disabled on the platform, preventing the system from downloading the required resources.

If it is possible on your system, can you please attemp to activate it. ( or confirm that it exists)

I checked my php.ini file and the directive was there, but turned off. I turned it on, saved the file, and made sure it was parsed correctly by checking php info:

Still no luck though, the directory the email link points to is empty and thus I still get a 404 error. :grimacing:

Did you find a solution for this? Im also getting 404 error on the email link.

@david any news regarding this issue?


Was anybody able to solve this? got a similar problem: zip file is not generated on a fresh install, (5.3.32-C67)


I think I may have found the explanation for this issue: my server is not running the gmp extension (and I can’t install it - shared hosting). I found that out when trying to update the app through Softaculous, which prevents updates because the extension is missing (I was previously doing manual installs and updates, so I was unware of that). The IN app itself never complains about the missing extension, and it actually tells me that the zip file is ready to download when I try to batch download documents, but then the zip file doesn’t exist, so that was a bit confusing.

Apparently, IN needs the gmp extension to bundle up docs in zip files, so with the extension missing it’s pointing to a nonexistent file, since it could not have been created.

BTW I think the same issue is discussed here too: Download invoices zip file not found - Self-Hosted | v5 - Discourse (