larksuite/cli · error

set_calendar: event_start must be a valid ISO 8601 timestamp

Error message

set_calendar: event_start must be a valid ISO 8601 timestamp

What it means

This error is returned by draft patch validation when a `set_calendar` operation supplies an `event_start` value that is non-empty but cannot be parsed by parseISO8601. The parser only accepts a small set of ISO 8601 layouts (RFC 3339 with seconds, RFC 3339 without seconds, and the same two without a timezone offset), so anything else — such as Unix epoch millis, 'YYYY/MM/DD', locale-formatted dates, or date-only strings like '2026-09-04' — fails. The original parse error is discarded, so the message does not reveal which layout was attempted.

Source

Thrown at shortcuts/mail/draft/model.go:355

		if !op.Target.hasKey() {
			return fmt.Errorf("remove_inline requires target with at least one of part_id or cid")
		}
	case "insert_signature":
		if strings.TrimSpace(op.SignatureID) == "" {
			return fmt.Errorf("insert_signature requires signature_id")
		}
	case "remove_signature":
		// No required fields.
	case "set_calendar":
		if strings.TrimSpace(op.EventSummary) == "" {
			return fmt.Errorf("set_calendar requires event_summary")
		}
		if strings.TrimSpace(op.EventStart) == "" || strings.TrimSpace(op.EventEnd) == "" {
			return fmt.Errorf("set_calendar requires event_start and event_end")
		}
		start, err := parseISO8601(op.EventStart)
		if err != nil {
			return fmt.Errorf("set_calendar: event_start must be a valid ISO 8601 timestamp")
		}
		end, err := parseISO8601(op.EventEnd)
		if err != nil {
			return fmt.Errorf("set_calendar: event_end must be a valid ISO 8601 timestamp")
		}
		if !end.After(start) {
			return fmt.Errorf("set_calendar: event_end must be after event_start")
		}
	case "remove_calendar":
		// No required fields.
	default:
		return fmt.Errorf("unsupported op %q", op.Op)
	}
	return nil
}

func isRecipientField(field string) bool {
	switch strings.ToLower(strings.TrimSpace(field)) {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Reformat event_start to RFC 3339 with seconds and an explicit offset, e.g. 2026-09-04T10:00:00+08:00 or 2026-09-04T02:00:00Z
  2. If you have an epoch number, convert it first: time.UnixMilli(ms).UTC().Format(time.RFC3339)
  3. Use one of the four accepted shapes: RFC3339 (2006-01-02T15:04:05Z07:00), 2006-01-02T15:04Z07:00, 2006-01-02T15:04:05, or 2006-01-02T15:04
  4. Validate the string with a strict ISO 8601 regex or time.Parse(time.RFC3339, s) before submitting the patch

Example fix

// before
ops := []Op{{Op: "set_calendar", EventSummary: "Sync", EventStart: "2026-09-04 10:00", EventEnd: "2026-09-04 11:00"}}
// after
ops := []Op{{Op: "set_calendar", EventSummary: "Sync", EventStart: "2026-09-04T10:00:00+08:00", EventEnd: "2026-09-04T11:00:00+08:00"}}
Defensive patterns

Strategy: validation

Validate before calling

func validTimestamp(s string) bool {
    _, err := time.Parse(time.RFC3339, s)
    return err == nil
}
if !validTimestamp(op.EventStart) {
    return fmt.Errorf("event_start must be RFC 3339, got %q", op.EventStart)
}

Prevention

When it happens

Trigger: Calling the draft patch (set_calendar op) with event_start set to a non-ISO-8601 string: epoch milliseconds (1725400000000), slash-formatted dates (2026/09/04 10:00), date-only values (2026-09-04), 'MMM D, YYYY' locale formats, or timestamps missing the T separator (2026-09-04 10:00:00).

Common situations: Passing a JavaScript Date.toString() or new Date().toISOString() variant the parser does not know; feeding backend timestamps that are epoch-based; copying human-readable dates from a calendar UI; forgetting timezone offsets in a format the layout list requires.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/dee213bf3f7ba946. Report an issue: GitHub.