Database backup with e. g. MariaDB to Hetzner StorageBox (Borg) fails #1294
Labels
No labels
blocked
breaking
bug
data loss
design finalized
good first issue
new feature area
question / support
security
waiting for response
No milestone
No project
No assignees
3 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
borgmatic-collective/borgmatic#1294
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What I'm trying to do and why
I ran into a problem with borgmatic 2.1.4 to backup MariaDB databases directly and it may be the same for e. g. Postgresql, etc.
That is the bug I get from the log and below that the analysis from Claude about the issue.
Steps to reproduce
No response
Actual behavior
Here is the analysis of Claude, what could be the culprit:
What's Actually Happening
Borgmatic's native mariadb_databases: hook does not simply run mariadb-dump to a file and then back it up. It uses a sophisticated FIFO (named pipe) + streaming mechanism:
This streaming approach is clever for large databases (no disk space needed for the dump), but it changes borgmatic's internal control flow significantly. During and after the archive creation, borgmatic does internal JSON parsing of Borg's output for checkpoints, archive renaming, and especially during prune/compact. When database hook stream processes are active, Borg's output can contain mixed text (SSH warnings, checkpoint messages, rename info) that trips up borgmatic's JSON parser -- resulting in the Expecting value: line 1 column 1 (char 0) error.
Why It Still Fails Without --json / --stats
The fix we applied (removing --json and --stats for database backups) addressed the external flags we pass. But borgmatic 2.1.4 also parses borg output internally in several places -- borgmatic/actions/json.py:parse_json() and within prune/compact modules that use --log-json internally. The SSH post-quantum warnings from Hetzner's StorageBox are being emitted by Borg and are polluting those internal JSON streams. Version 2.1.2 partially fixed this (#1260), but clearly not completely for the database hook code path.
The Right Fix (Not a Downgrade)
You're absolutely right that downgrading is not a good approach. And here's the thing -- we already have a working pattern in our codebase for exactly this: the MSSQL database type. Since borgmatic has no native MSSQL support, we handle it via commands: hooks that dump to a temp directory and include that directory in source_directories. This approach:
Expected behavior
No response
Other notes / implementation ideas
No response
borgmatic version
2.1.4
borgmatic installation method
Debian package
Borg version
borg 2.0.0b20
Python version
No response
Database version (if applicable)
No response
Operating system and version
Ubuntu 22
Thanks for taking the time to file a ticket on this. So far I haven't been able to reproduce the problem. A few questions:
Thank you for the fast reply!
I have gotten the answer with Claude Opus 4.6 (God, way better than I could ever have written it myself!!).
One addition though: If you want to, I can create you a Hetzner Storagebox and send you the credentials in a PM, if you want to test. Hetzner Storageboxes are quite popular, not only in Germany as they are dirt cheap compared to e. g. Azure, AWS, etc AND they support Borg on their side (SSH configuration).
1. Borgmatic configuration (redacted credentials)
2. Does the problem go away when you disable the database hooks?
Yes, completely. We have a second backup job (file-only, no database hooks) that targets the exact same Hetzner StorageBox repository via the same SSH connection and it always succeeds. Only the database backup job that uses
mariadb_databases:fails with the JSON parse error. We also confirmed that switching these same MariaDB sources to acommands:hook approach (dump to temp file, then include that directory insource_directories) works perfectly against the same repo — so the issue is specific to the native FIFO/streaming code path.3. Does the problem occur for other non-MariaDB database hooks?
We have not tested with PostgreSQL or MySQL hooks against this specific repository, so we cannot confirm. However, given that the error occurs during the prune/compact phase (not during the dump itself), and the suspected cause is SSH warnings polluting Borg's JSON output, we believe it would affect any native database hook when the remote emits non-JSON stderr/stdout during those phases.
4. What does the borgmatic command-line look like?
Our UI runs borgmatic as:
We initially used
--stats --jsonfor all backups. After seeing the error, we tried removing--stats --jsonfor database backup jobs (running with just--verbosity 1), but the error still occurred. This suggests borgmatic is parsing JSON internally (e.g., during prune/compact or archive rename operations) regardless of whether we pass--jsonexternally.5. Full logs from one run (chronological order)
Note the pattern: the SSH post-quantum warnings appear twice (once during the initial connection for archive creation, once during a subsequent SSH session — likely prune or compact), and then immediately the JSON parse error fires. The
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)is a Python error that occurs whenjson.loads()receives an empty string or non-JSON text.Earlier runs showed the same pattern with additional context — the SSH warnings appear during both the create and prune/compact phases, and the error consistently fires right after warnings during the post-create phase.
6. MariaDB version
The MariaDB servers are running in Docker containers (images based on
mariadb:10.11ormariadb:11). The exact version shouldn't matter though, becausemariadb-dumpitself completes successfully — the dump data reaches Borg. The JSON parse error occurs later, during borgmatic's internal processing of Borg's output.Additional context that may help reproduce:
borg1, configured vialocal_path: /usr/bin/borg1). Note: my original bug report incorrectly mentioned borg 2.0.0b20 — that's also installed in our container but not used for this backup job.mariadb_databases:hooks. It has never succeeded.One important correction for you to make in the original GitHub issue: I had listed Borg version as
2.0.0b20, but the actual backup job useslocal_path: /usr/bin/borg1which is Borg 1.4.0.PS: I am working on the "Borgmatic (Director) UI", a project for a great Web UI for Borgmatic. It seems to be working quite well (still in testing phase myself).
I made it open source and free for personal use (community edition). There is a commercial version for added "Director Mode" to orchestrate multiple servers.
Dan was so nice to put a link on the borgmatic website to the project:
https://github.com/SpeedbitsInfinityTools/borgmatic-ui-community
Thanks for including all of these details. The good news is I got a repro! I appreciate the offer of Hetzner Storage Box credentials, but it turned out I have access to another server that gives the same post-quantum SSH warning, and the error reproduces when using a remote repo there. Interestingly, it reproduces even without the MariaDB hook enabled. So hopefully this is indeed the same issue and not just one that appears very similar.
I'll dig into this and hopefully figure out what's going on.
That's correct. borgmatic gets logs from Borg in JSON (unconditionally) and then displays it to the user as either JSON or plaintext depending on what they asked for.
Also, in the future please provide
--verbosity 2logs in tickets. I should've mentioned that to begin with. No need to do that now, since I have a local repro.Actually, I take that last part back. If you could provide
--verbosity 2logs, that would help me confirm that I've indeed reproduced the same issue you're experiencing rather than some related issue. Thanks!Looks like this was a regression caused by changes from #1264. I have a fix in main that will be part of the next release. Thanks for your patience here!
Ok, so you dont need the --verbosity 2?!
Last question: how often do you release, i. e. when appr. would you expect the next release?
Thank you for your great work!!!
The
--verbosity 2log would still be useful to confirm. And releases are usually every couple of weeks, although that can vary. If you need a workaround in the meantime... I suspect that the problem for you is occurring within thecheckaction, so you could try skipping checks.I had the same issue, and applying your patch fixed it for me. For me it happened on the
createaction and I used a Postgres DB.@PyroDev Thanks for weighing in. I'm glad to hear the patch fixed it for you!
Released in borgmatic 2.1.5!