Manual backup via POST /api/hosts/{id}/jobs sends paths:null — "Fatal: nothing to backup" #55

Closed
opened 2026-08-22 13:19:32 +01:00 by bobby · 0 comments

Summary

POST /api/hosts/{id}/jobs with {"kind":"backup"} dispatches a job with no source paths, so restic aborts immediately. The per-source-group alias POST /api/hosts/{id}/source-groups/{gid}/run works correctly on the same host with the same configuration.

This is the same shape as #36 (manual forget not receiving forget_groups), but for the backup kind: the manual dispatch path does not populate the structured payload that the scheduled path does.

Reproduce

On a host with a healthy source group (includes populated, backups succeeding on schedule):

curl -X POST -H 'Content-Type: application/json' -d '{"kind":"backup"}' \
  https://<server>/api/hosts/<host-id>/jobs
# -> 202 {"job_id":"<job-id>","status":"queued"}

Observed

Job fails in ~15ms:

# job <job-id> · kind backup · status failed
# started  2026-08-22T12:09:58.068Z
# finished 2026-08-22T12:09:58.083Z
# 1 log lines

ERR {"message_type":"exit_error","code":1,
     "message":"Fatal: nothing to backup, please specify source files/dirs"}

Agent log shows the payload arrived empty:

{"level":"INFO","msg":"agent: accepting backup job","job_id":"<job-id>",
 "paths":null,"excludes":null,"tag":""}

Contrast — the source-group alias works

Same host, same moment, via POST /api/hosts/{id}/source-groups/{gid}/run:

{"level":"INFO","msg":"agent: accepting backup job","job_id":"<job-id>",
 "paths":["/home/steve/services","/var/lib/docker/volumes","/root"],
 "excludes":null,"tag":"default"}

That job succeeded. Note tag is also empty in the failing case, so even if paths were supplied the snapshot would be untagged and fall outside the tag-scoped retention groups used by forget.

Impact

Low-to-medium in consequence but high in confusion: {"kind":"backup"} is the most obvious way to trigger an ad-hoc backup from the API, it is accepted with 202, and it always fails. The failure also raises a backup_failed alert, so routine API use generates noise that looks like a real backup problem.

For a host with multiple source groups the fix presumably needs to either back up all groups or require the caller to name one — worth deciding explicitly rather than defaulting.

Suggested fix

Mirror what #36 did for forget: have dispatchJob populate the structured payload for kind: backup from the host's source groups (paths, excludes, tag), and reject with a structured error when the host has no usable source group — rather than dispatching a job that cannot succeed.

Environment

  • Server v1.2.1, agent v1.2.1, restic 0.18.1
  • Reproduced before and after an unrelated source-group edit, so not configuration-specific
  • Related: #36 (same class, forget kind)
## Summary `POST /api/hosts/{id}/jobs` with `{"kind":"backup"}` dispatches a job with **no source paths**, so restic aborts immediately. The per-source-group alias `POST /api/hosts/{id}/source-groups/{gid}/run` works correctly on the same host with the same configuration. This is the same shape as #36 (manual forget not receiving `forget_groups`), but for the backup kind: the manual dispatch path does not populate the structured payload that the scheduled path does. ## Reproduce On a host with a healthy source group (`includes` populated, backups succeeding on schedule): ```bash curl -X POST -H 'Content-Type: application/json' -d '{"kind":"backup"}' \ https://<server>/api/hosts/<host-id>/jobs # -> 202 {"job_id":"<job-id>","status":"queued"} ``` ## Observed Job fails in ~15ms: ``` # job <job-id> · kind backup · status failed # started 2026-08-22T12:09:58.068Z # finished 2026-08-22T12:09:58.083Z # 1 log lines ERR {"message_type":"exit_error","code":1, "message":"Fatal: nothing to backup, please specify source files/dirs"} ``` Agent log shows the payload arrived empty: ```json {"level":"INFO","msg":"agent: accepting backup job","job_id":"<job-id>", "paths":null,"excludes":null,"tag":""} ``` ## Contrast — the source-group alias works Same host, same moment, via `POST /api/hosts/{id}/source-groups/{gid}/run`: ```json {"level":"INFO","msg":"agent: accepting backup job","job_id":"<job-id>", "paths":["/home/steve/services","/var/lib/docker/volumes","/root"], "excludes":null,"tag":"default"} ``` That job succeeded. Note `tag` is also empty in the failing case, so even if paths were supplied the snapshot would be untagged and fall outside the tag-scoped retention groups used by forget. ## Impact Low-to-medium in consequence but high in confusion: `{"kind":"backup"}` is the most obvious way to trigger an ad-hoc backup from the API, it is accepted with `202`, and it always fails. The failure also raises a `backup_failed` alert, so routine API use generates noise that looks like a real backup problem. For a host with multiple source groups the fix presumably needs to either back up all groups or require the caller to name one — worth deciding explicitly rather than defaulting. ## Suggested fix Mirror what #36 did for forget: have `dispatchJob` populate the structured payload for `kind: backup` from the host's source groups (paths, excludes, tag), and reject with a structured error when the host has no usable source group — rather than dispatching a job that cannot succeed. ## Environment - Server `v1.2.1`, agent `v1.2.1`, restic `0.18.1` - Reproduced before and after an unrelated source-group edit, so not configuration-specific - Related: #36 (same class, forget kind)
steve closed this issue 2026-08-22 13:45:04 +01:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: steve/restic-manager#55