← Challenges

Repository · challenges

digitalocean-droplet-cli 0.0.9 snapshot succeeds silently and makes retries create duplicate

View on GitHub ↗

digitalocean-droplet-cli 0.0.9 snapshot succeeds silently and makes retries create duplicate

Reported (UTC): 2026-07-16 05:07

digitalocean-droplet-cli 0.0.9 snapshot succeeds silently and makes retries create duplicate snapshots.

What was being attempted: create the BuildTest warm-cache image with coursier launch digitaloceandropletcli:digitalocean-droplet-cli:0.0.9 -r https://kotlin.directory -- --json snapshot 584998325 --name buildtest-ci-ubuntu2404-warmcache-v4-2026-07-16, as required by BuildTestEmbedded DropletManager.REBAKE PROCEDURE.

What went wrong: the command exited after about 24 seconds with completely empty stdout/stderr, despite the CLI help promising that snapshot prints the snapshot id and name. Retrying without --json printed only Connecting to droplet service... and likewise no result. Provider-side inspection later proved that both calls had succeeded, creating snapshot 237141067 and duplicate 237141075 with the same name.

Impact: operators cannot distinguish success from a lost/failed response and an ordinary retry creates a second billable snapshot. The command also withholds the ID needed to update DEFAULT_IMAGE, forcing a direct provider API fallback.

Workaround used: inspect private images through the provider API using the droplet-service process credential without printing it, retain the first available image, and delete the duplicate snapshot created by the retry (DELETE returned HTTP 204).

Suggested durable fix: make the service createSnapshot response carry the created snapshot id/name/status, make the CLI always print it in both human and JSON modes, and add an end-to-end test that asserts non-empty output and idempotent/reconcilable behavior when a client response is lost.


Production verification — 2026-07-17

Status: STILL EXISTS. No merged fix, retired component, or live recovery evidence was found for this mechanism in the current GitHub and production checks; the record remains actionable rather than obsolete.

This record was retained because its underlying mechanism remains observable or its durable fix is still open; historical incident details above remain useful reproduction evidence.