Daemon tick wedges on deleted-file row with NULL sha256 ("missing previous sha256") #23
Labels
No labels
agent
blocked
agent
new
agent
review
agent
working
complexity
high
complexity
low
priority
high
priority
low
priority
medium
risk
high
risk
low
risk
medium
type
bug
type
chore
type
feature
type
security
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
tfks/dropbear#23
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?
Symptom
A daemon root wedges on every tick with:
The tick fails uniformly and never recovers — the entire tick errors out each interval, so the root stops making progress.
Root cause
The error is the defense-in-depth invariant guard in
deletedRowToTombstoneEntry(internal/upload/tombstone.go:68). Adeletedrow oftype='file'is required to carry asha256so a valid tombstone can be built for it. The offending row had:status = 'deleted'type = 'file'sha256 IS NULLlast_synced_manifest IS NOT NULL(inferred — see below)That combination is supposed to be unreachable: the walker only classifies a row
deletedwhen it already carries a committed baseline, and a baselined row always has a sha256. Rows that wentnew→deleted(never baselined) are swept byPurgeUnbaselinedDeleted.The two sweepers miss each other.
PurgeUnbaselinedDeletedonly deletes deleted rows wherelast_synced_manifest IS NULL(internal/state/write.go:393). This row has a baseline pointer set and a NULL sha256, so the purge doesn't catch it and the tombstone builder rejects it — permanently. One malformed row wedges the whole root.The file (
hi.mom) existed only in the server's local.dropbear/state.sqlite. Verified against the R2 bucket: not in the laptop manifest, not in the server's published manifest (last written 2026-07-15), and no server tombstones exist at all. It is a ghost row that was never published anywhere — most likely produced by an earlier/buggy walk during development, and probably not reachable by current code.Prescription (operator remediation)
Because the file exists nowhere and no tombstone is warranted, drop the poisoned row from the affected root's state DB. On the affected host:
Next tick goes green.
Suggested hardening (if not already impossible)
Suspected to be an impossible state under current code — needs confirmation. If it can still occur:
PurgeUnbaselinedDeleted(or add a sibling sweep) to also dropdeleted+type='file'+sha256 IS NULLrows — they can never produce a valid tombstone.If it is confirmed unreachable now, at minimum keep this as a known-recovery note for the invariant guard.