larksuite/cli · error

set_calendar: event_end must be a valid ISO 8601 timestamp

Error message

set_calendar: event_end must be a valid ISO 8601 timestamp

What it means

Same parse failure as error 840 but for the `event_end` field of a `set_calendar` operation: the value is non-empty yet parseISO8601 cannot match it against any of the four supported layouts (RFC 3339 with/without seconds, with/without timezone offset). The library validates both endpoints up front so a malformed event never reaches the calendar API.

Source

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

		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)) {
	case "to", "cc", "bcc":
		return true
	default:
		return false

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Reformat event_end to RFC 3339, e.g. 2026-09-04T11:00:00Z or with explicit offset 2026-09-04T11:00:00+08:00
  2. Convert epoch numbers first: time.Unix(sec).UTC().Format(time.RFC3339)
  3. Check that event_start and event_end are produced by the same formatting code path — often one is fixed while the other still uses a legacy format
  4. Pre-validate with time.Parse(time.RFC3339, s) client-side

Example fix

// before
end := fmt.Sprintf("%v", endTime) // "2026-09-04 11:00:00 +0800 CST"
// after
end := endTime.UTC().Format(time.RFC3339) // "2026-09-04T03:00:00Z"
Defensive patterns

Strategy: validation

Validate before calling

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

Prevention

When it happens

Trigger: set_calendar op with event_end like '1725400000000' (epoch), '2026/09/04 11:00', '2026-09-04' (date-only), 'Fri Sep 04 2026 11:00:00 GMT+0800', or any string not matching one of the four time.Parse layouts in parseISO8601.

Common situations: Generating end times with a different formatter than start times; timezone libraries outputting offsets like '+08' (single-digit hours) instead of '+08:00'; serializing dates via fmt.Sprintf("%v", t) which yields a full Go date string the parser rejects.

Related errors


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