Skip to content

bug: complete/cancel silently no-op on repeating to-dos (Things rejects the update; CLI reports success) #129

Description

@ryanlewis

Summary

things cancel <uuid> exits 0 and prints nothing, but the task's status stays open. Seen on two specific long-lived tasks; things complete on the same UUIDs works, so it is not the Things URLs auth-token path.

things edit <uuid> --cancel behaves identically — silent exit 0, no state change.

Version

things 0.5.2 (commit 87c9bca742a698c5ef5ca4cf5f779e525f7b9d0a, built 2026-08-09T00:44:11Z)

Observed

Observed with two tasks in the same project (for my own notes: "AFC"), start: 2 (Someday), tagged Work, both created 2026-04-23:

$ things cancel W1gBDJPFpwUQrdP5Am5K7J
$ echo $?
0
$ things show W1gBDJPFpwUQrdP5Am5K7J -j | jq -r .status
open

Repeated three times over several minutes, and via things edit <uuid> --cancel. Always exit 0, always still open. things complete on the same UUID transitions to completed immediately.

Not reproducible on fresh tasks

I could not trigger it with newly created tasks. All of these cancelled correctly:

Repro task project when tags result
zz-cancel-repro cancelled
zz-repro-someday-noproj someday cancelled
zz-repro-someday-proj <project> someday cancelled
zz-repro-anytime-proj <project> anytime cancelled
zz-repro-tagged <project> someday Work cancelled

So project membership, Someday bucket, and tags are each ruled out individually.

Diff between a failing and a working task

Only material differences are tags and a non-zero index / todayIndex:

FAILING                             WORKING
"start": 2                          "start": 2
"startBucket": 0                    "startBucket": 0
"tags": ["Work"]                    (none)
"index": -127                       "index": 0
"todayIndex": -836                  "todayIndex": 0
"creationDate": 2026-04-23          "creationDate": 2026-08-10

The tagged repro row above shows tags alone isn't sufficient. That leaves the non-zero todayIndex on an old task as the remaining suspect — possibly a task that has previously been in Today and carries state the cancel payload doesn't account for.

Why it's silent

Almost certainly the same root cause as #19: the URL scheme gives us no callback, so a rejected update is indistinguishable from a successful one and we report exit 0 either way. Even without a fix for the cancel itself, cancel should not claim success it cannot verify — a post-write read-back and a non-zero exit on unchanged status would surface this class of failure.

Suggested

  1. Read back status after cancel / edit --cancel and exit non-zero with a clear message if unchanged.
  2. Work out why the update payload is rejected for these tasks — compare the emitted URL for a failing vs working UUID.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions