Skip to content

edit --list / --list-id fails with ReminderKit error -3002 when a shared list is on either end of the move #104

Open

Description

@paulchiu

Bug

Moving a reminder between lists fails with com.apple.reminderkit error -3002 when the source or the target list is a shared/collaborative list, and succeeds when neither is. remindctl 0.3.8, macOS 27.0.1 build 26A434, Apple Silicon, one iCloud account with no On My Mac or work account, remindctl status reporting full-access.

Repro

# Shopping is a shared iCloud list; Apps is a plain iCloud list.
remindctl add "rem-3002-repro" --list Shopping --json --no-input
#   id 1A827CE7-6B73-4764-810E-A36DCEB4114D

remindctl edit 1A827CE7 --list Apps --json --no-input
#   exit code 1
#   stderr: The operation couldn't be completed. (com.apple.reminderkit error -3002.)
#   stdout: empty

The reminder stays in Shopping, and retries give the same error rather than a transient failure. --list and --list-id both fail, and passing the full UUID rather than a prefix makes no difference. Non-list edits on the same reminder work, so the save path itself is fine:

remindctl edit 1A827CE7 --priority high --json --no-input   # ok
remindctl edit 1A827CE7 --notes "ok" --json --no-input      # ok

Move direction is not the variable, sharing is:

Move Result
non-shared → non-shared works
shared → non-shared -3002
non-shared → shared -3002

Likely cause

Public EventKit has no move API. EKEventStore exposes saveReminder:, removeReminder:, saveCalendar: and removeCalendar: only, so the only way to move is to set the settable EKCalendarItem.calendar and save, which appears to be what edit --list does through CommandHelpers.listTarget and the update path. The upstream analysis in BRO3886/go-eventkit#13 is that EventKit rejects that save when a shared list is on either end, because it treats a shared/collaborative list as effectively its own source, and EventKit's own error constants document the neighbouring restrictions (EKErrorCalendarSourceCannotBeModified, EKErrorSourceDoesNotAllowCalendarAddDelete, and EKCalendar.h's note that you cannot move to another source).

Two things point at the sharing boundary rather than a general save problem. AppleScript's native move command succeeds on the same machine, account and lists, including between two shared lists, which suggests a sanctioned reparent exists below EventKit. The same matrix is reported in BRO3886/rem#50, with the root cause written up in BRO3886/go-eventkit#13; see also viticci/remctl#13 and FradSer/mcp-server-apple-events#81. Nothing here is documented by Apple.

Expected

Either the move works, or the failure names the actual constraint.

  1. Preferred, and within the project's public-EventKit stance: detect the boundary before attempting the save and fall back to copy and delete, printing a warning that the new reminder gets a new ID. BRO3886/go-eventkit@6a7610a implements this as moveViaCopy and is a workable reference.
  2. At minimum, replace the bare -3002 with a message that names the shared-list boundary, since the current error gives no hint where to look.
  3. If the limitation is accepted as-is, two smaller gaps are worth closing with it. remindctl list --json returns only id, overdueCount, reminderCount and title, so a caller cannot see which lists are shared; an isShared field would let scripts detect the case. And docs/commands.md documents remindctl edit 4A83 --list Office with no caveat, while the README's "EventKit Limits" list would be the natural home for it.

Activity

  1. added
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    P2Normal priority bug or improvement with limited blast radius.
    clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.
    clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.
    clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.
    clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.
    impact:ux-frictionUser-facing flow adds avoidable confusion or support burden without fully blocking progress.
    issue-rating: 🦪 silver shellfishThin issue quality; more reproduction proof or environment detail is needed.
    and removed
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    on Oct 17, 2026
  2. clawsweeper commented on Oct 17, 2026

    @clawsweeper

    Codex review: this still needs some work.

    Summary
    This issue establishes a specific v0.3.8 move failure, and current main retains the same save path without contextual handling.

    Reproducibility: The reporter supplies a controlled affected-release reproduction, corroborated by external investigation; current source proves the reassignment and raw-error path, but cannot establish when EventKit rejects the save.

    Maintainer decision needed

    • Question: Should shared-list move failures receive contextual diagnostics first, or should edit introduce a copy-and-delete fallback?
    • Recommendation: Improve diagnostics first: Preserve the underlying error, explain possible shared-list or account restrictions, and document recovery through Reminders.app.
    • Why: The preferred fallback changes identity and relies on sharing detection that the external reference obtains privately, while this repository explicitly uses public EventKit.

    Next step
    Choose diagnostic-first handling or an explicit identity-changing fallback, then establish a failing shared-list move regression on macOS.

    Review details

    Best possible solution:

    Provide an actionable move-failure diagnostic and documented limitation first, with any identity-changing fallback separately approved.

    Do we have a high-confidence way to reproduce the issue?

    The reporter supplies a controlled affected-release reproduction, corroborated by external investigation; current source proves the reassignment and raw-error path, but cannot establish when EventKit rejects the save.

    Is this the best way to solve the issue?

    Contextual diagnostics are the safest initial repair; automatically copying and deleting cannot be treated as a transparent move, and -3002 must not be described as uniquely identifying sharing.

    AGENTS.md: not found in the target repository.

    Remaining risk / open question:

    • The sharing-dependent EventKit rejection was not independently reproduced on macOS during this review.
    • Copy-and-delete changes reminder identity, may omit inaccessible metadata, and needs defined recovery when deletion fails.
    • A public-EventKit mechanism for reliable sharing detection remains unestablished; matching -3002 alone cannot prove sharing.

    Codex review notes: model internal, reasoning medium; reviewed against 61fb13efbc25.

    Label changes

    Label changes:

    No label changes.

    Label justifications:

    • P2: Shared-list moves fail in a documented CLI operation while ordinary moves and other edits remain usable.
    • impact:ux-friction: The raw platform error provides no useful explanation or recovery guidance.
    Evidence reviewed

    Acceptance criteria:

    • Establish a failing regression for a rejected list-move save before implementing diagnostic handling.
    • On macOS, exercise shared-to-plain and plain-to-shared moves using both --list and --list-id; verify the original reminder remains intact after rejection.
    • Verify plain-to-plain moves and priority/notes edits still succeed, and failed JSON moves produce exit code 1 with empty stdout.
    • Run swift test and make check after implementation.
    • Run git diff --check and validate the updated command documentation.

    What I checked:

    • Specific affected-release report: The reporter supplies v0.3.8, macOS 27.0.1, full-access authorization, failing moves in both shared-list directions, successful ordinary moves, and successful non-list edits; both discussion comments are automation comments.
    • Current main retains the reported implementation: updateReminder assigns the destination calendar at lines 168–171 and saves at line 177 without move-specific handling; these files are unchanged from v0.3.8, and GitHub confirms this checkout is current main. (Sources/RemindCore/EventKitStore.swift:168, 61fb13efbc25)
    • Raw platform errors reach the caller: Edit prints its result only after updateReminder succeeds; the router catches a thrown save error, prints localizedDescription, and returns exit code 1. (Sources/remindctl/CommandRouter.swift:78, 61fb13efbc25)
    • Public API boundary and documentation gap: README explicitly commits to public EventKit APIs and lists unavailable Reminders metadata; docs/commands.md demonstrates both move options without a shared-list caveat, while ListSummary exposes no sharing state. (README.md:295, 61fb13efbc25)
    • External investigation corrects the original move theory: In rem update --list (move between lists) always fails with com.apple.reminderkit error -3002 BRO3886/rem#50, binarytested supplies the controlled sharing matrix; BRO3886 subsequently reports that private reparenting also fails and AppleScript succeeds by changing the reminder ID.
    • Fallback reference belongs to rem: The reported short SHA resolves in BRO3886/rem, not go-eventkit: moveViaCopy creates a replacement and deletes the original, and its commit describes sharing detection through private REMList properties; this is an external reference, not a target dependency or inherited repository policy. (internal/service/reminders.go:323, 6a7610a377c7)
    How this review workflow works
    • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
    • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
    • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
    • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
    • Maintainers can also comment @clawsweeper review to request a fresh review only.
    • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge; those execution lanes are retired.
    • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

    Reviewed October 18, 2026, 1:58 PM ET / 17:58 UTC.

  3. added
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    and removed
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    on Oct 17, 2026
  4. 2 remaining items

  5. added
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    and removed
    clawsweeper:intake:bugPreliminary submission classification; full source review pending.
    on Oct 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:ux-frictionUser-facing flow adds avoidable confusion or support burden without fully blocking progress.issue-rating: 🦪 silver shellfishThin issue quality; more reproduction proof or environment detail is needed.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions