Skip to content

Calendar: no way to create or update an event with NO reminders (useDefault:false + empty overrides) #1002

Description

@jamespublishlab

Problem

There is no way to create or update a calendar event with no reminders.

The Calendar API distinguishes three states:

reminders payload Meaning
absent use the calendar's defaultReminders
{"useDefault": false, "overrides": [{...}]} these specific reminders
{"useDefault": false, "overrides": []} no reminders at all

gog can express the first two. The third is unreachable, because an empty
--reminder is treated as "unspecified" rather than as "none".

Why it matters

Google applies a calendar's single defaultReminders list to all-day events
created via the API, ignoring the separate "All-day event notifications" setting
shown in the web UI. So an all-day event created by gog on a calendar whose
timed default is popup 10m inherits that popup — and a 10-minute popup on an
all-day event fires at 23:50 the evening before.

There is no way to avoid this from gog: clearing the all-day setting in the UI
has no effect (the API path uses defaultReminders), and the timed default has
to stay for real meetings.

Reproduction

# a calendar whose defaultReminders is [{popup, 10}]
gog calendar create primary --summary "all-day marker" --all-day \
    --from 2030-05-01 --to 2030-05-02 --json -n

The request body contains no reminders key, so the default is inherited:

"event": {
  "end":     {"date": "2030-05-02"},
  "start":   {"date": "2030-05-01"},
  "summary": "all-day marker"
}

Attempting to suppress it:

gog calendar create primary ... --reminder ""    # -> no reminders field at all
gog calendar update primary <id> --reminder ""   # -> {"useDefault": true}

The update case is the surprising one: --reminder "" documents as "Set empty to
clear", but it sets useDefault: true, which restores the calendar default
rather than clearing reminders.

Cause

buildReminders in internal/cmd/calendar_build.go returns nil for an empty
input, and nil means "use calendar defaults":

//nolint:nilnil // nil return is intentional: nil means "use calendar defaults"
func buildReminders(reminders []string) (*calendar.EventReminders, error) {
	if len(reminders) == 0 {
		return nil, nil
	}
	var filtered []string
	for _, r := range reminders {
		if strings.TrimSpace(r) != "" {
			filtered = append(filtered, r)
		}
	}
	if len(filtered) == 0 {
		return nil, nil
	}
	...

EventReminders{UseDefault: false, Overrides: overrides} is only ever
constructed with at least one override, so overrides: [] is unreachable. In
calendar_update_patch_plan.go a nil becomes {UseDefault: true}.

Confirmed identical on 0.12.0 and 0.37.0.

Suggested fix

A --no-reminder / --reminders-none flag (or a reserved --reminder none)
that produces:

"reminders": {"useDefault": false, "overrides": []}

with UseDefault in ForceSendFields, exactly as the existing override path
already does.

Workaround

Calling the API directly with that body works — Google accepts an empty
overrides list without complaint, so the limitation is purely in how the flag is
interpreted:

PATCH https://www.googleapis.com/calendar/v3/calendars/{calendarId}/events/{eventId}
{"reminders": {"useDefault": false, "overrides": []}}

Version

gog v0.37.0 (Homebrew), macOS arm64

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Normal priority bug or improvement with limited blast radius.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.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions