Support

Akeeba Backup for Joomla!

#43244 S3 upload fails with "Missing input parameters" on an empty final .jpa when archive size is an exact multiple of the part size

Posted in ‘Akeeba Backup for Joomla!’
This is a public ticket

Everybody will be able to see its contents. Do not include usernames, passwords or any other sensitive information.

Environment Information

Joomla! version
Joomla! 5.4.7 Stable
PHP version
8.3.31
Akeeba Backup version
10.3.7

Latest post by nicholas on Wednesday, 05 August 2026 01:09 CDT

fdinkler
Environment
- Akeeba Backup Professional 10.3.7
- Joomla 5.x, PHP 8.x, Linux/cPanel host
- Post-processing: Upload to Amazon S3 (signature v4, "Disable multipart uploads" enabled, ACL bucket-owner-full-control)
- Archiver: JPA, split archive enabled, part size 20 MiB (20,971,520 bytes)

What I did
Ran a full backup on this profile. The backup builds the archive fine and every numbered part (.j01 … .j230) uploads to S3 successfully.

What happened
Post-processing aborts the whole backup on the final .jpa part:

Failed to process file ...-.jpa
Error received from the post-processing engine:
Missing input parameters
[Akeeba\S3\Exception\CannotPutFile] .../vendor/akeeba/s3/src/Connector.php(86)
Failed Smart algorithm on Akeeba\Engine\Core\Domain\Finalization

The error is thrown client-side before anything is sent to Amazon (it is not an S3/HTTP response error).

What I found (root cause)
The archive total was an exact multiple of the part size, so the archiver produced a zero-byte trailing .jpa part:
- Part size: 20,971,520 bytes
- Total archive (from the log): 4,823,449,600 bytes
- 4,823,449,600 / 20,971,520 = 230.000 exactly -> .j01….j230 are full, .jpa is 0 bytes

The S3 engine then rejects the empty part:
- engine/Postproc/Amazons3.php:153 -> $fileSize = @filesize($localFilepath); (0 for the empty .jpa)
- simpleUpload() calls Input::createFromFile() and putObject()
- vendor/akeeba/s3/src/Connector.php:82 -> the guard `if ($input->getSize() redentials/config problem and sent me looking in the wrong place at first.

I've attached the full Akeeba Backup debug log for this run.

fdinkler
Here's the bug in the source, vendor/akeeba/engine/engine/Archiver/BaseArchiver.php (the split-write loop, ~lines 560–585, mirrored at 717–748):

while ($bytesLeftInData > 0)
{
$bytesWritten = $this->fwrite($this->fp, $zdata, min($bytesLeftInData, $freeSpaceInPart));
$freeSpaceInPart -= $bytesWritten;
$bytesLeftInData -= $bytesWritten;
...
if ($freeSpaceInPart LE 0) // fires even when bytesLeftInData is now 0
{
$this->createAndOpenNewPart(); // creates a superfluous EMPTY part
$freeSpaceInPart = $this->getPartFreeSize();
}
}

fdinkler
When the final chunk of archive data fills a part exactly, freeSpaceInPart hits 0 at the same moment bytesLeftInData hits 0.
The if ($freeSpaceInPart LE 0) check isn't guarded by "is there more data?", so it eagerly opens a new part that never receives any bytes. That empty part becomes the final .jpa, and the S3 engine's getSize() LE 0 guard then aborts the whole backup

nicholas
Akeeba Staff
Manager

Thank you for the exceptionally good bug report — you pointed straight at the offending line, which made this quick to confirm. It is a genuine bug and it's now fixed.

Your existing backup is fine. The empty trailing part is not a sign of a corrupt archive. All 4,823,449,600 bytes of your data are present in parts .j01 through .j230, and the archive header correctly declares 231 parts, all of which exist on disk. Nothing was lost. The zero-byte part carries no data, so extraction reads right past it. The only thing the empty part actually breaks is the upload: our S3 library rejects any file of zero length before it ever hits the wire, which is where "Missing input parameters" comes from, and that failure is what marks the whole backup as failed.

What's actually going on. Your diagnosis of the mechanism was correct: the split-write loop rotates to a new part whenever the current one fills up, without first checking whether there is any data left to write. When both run out on the same iteration, you get a part that never receives a byte, and JPA finalisation renames the last part to .jpa — so the surplus empty part becomes your final archive.

One refinement, which matters because it explains why this is so rare. It isn't triggered by the total archive size being an exact multiple of the part size. A write that exactly fills a part is already handled correctly and returns without rotating. The condition is narrower: a single compressed block has to span a part boundary and end exactly on the following one. That is a much less likely coincidence than the total size lining up, which is why this has gone unnoticed for years despite split archives being common. It also means it depends on your data, not just your settings. To put it into perspective, this is about 15 years old, you are the first person to hit it – millions of backups before someone hit it.

Until the fix ships, simply re-running the backup will most likely succeed, since the compressed data shifts as your site changes. If you want to be more deliberate, change the part size — 16 MiB or 25 MiB instead of 20 MiB. Any change perturbs the arithmetic and the coincidence will not recur.

The fix is in the backup engine and will be in the next release. I also fixed the same latent problem in the JPS (encrypted archive) writer, where it was producing a similarly pointless trailing part. Both are covered by regression tests now.

Nicholas K. Dionysopoulos

Lead Developer and Director

🇬🇷Greek: native 🇬🇧English: excellent 🇫🇷French: basic • 🕐 My time zone is Europe / Athens
Please keep in mind my timezone and cultural differences when reading my replies. Thank you!

fdinkler
Thanks for the reply. Thanks Claude Code for the detailed bug report.
I should have purchased a lottery ticket...
Fred

nicholas
Akeeba Staff
Manager

Back when I had first written that code, about 16 years ago, I remember having found that problem. However, at the time, fixing it was breaking upload on part finalization. At that point I decided the issue is both extremely unlikely and self-healing: a new full backup is by definition a few bytes longer because of the failed backup's database record now being part of the backup. When I reworked the upload years later I had fully forgotten about this. As soon as I saw your ticket I knew exactly what it was.

Once again thank you for the report! I am not against using AI when it's a genuinely useful tool, and that was indeed one of those cases. If anyone else is reading, that's how you use AI coding assistants, folks.

And yes, do buy that lottery ticket. The issue you hit had longer odds than most lotteries :)

Nicholas K. Dionysopoulos

Lead Developer and Director

🇬🇷Greek: native 🇬🇧English: excellent 🇫🇷French: basic • 🕐 My time zone is Europe / Athens
Please keep in mind my timezone and cultural differences when reading my replies. Thank you!

Support Information

Working hours: We are open Monday to Friday, 9am to 7pm Cyprus timezone (EET / EEST). Support is provided by the same developers writing the software, all of which live in Europe. You can still file tickets outside of our working hours, but we cannot respond to them until we're back at the office.

Support policy: We would like to kindly inform you that when using our support you have already agreed to the Support Policy which is part of our Terms of Service. Thank you for your understanding and for helping us help you!