larksuite/cli · error

date %q must be ISO yyyy-mm-dd: %w

Error message

date %q must be ISO yyyy-mm-dd: %w

What it means

For values containing a 'T' (ISO datetime), isoDateToSerial first parses the date portion with layout 2006-01-02. If that base date is malformed (e.g. "2026-13-01T..." or "01/31/2026T..."), the underlying time.Parse error is wrapped in this message. Callers add row/column context in the typed validation error.

Source

Thrown at shortcuts/sheets/lark_sheet_table_io.go:781

// `T` separator (`2024-01-15T00:00:00.000`, `2024-01-15T08:30:00+08:00`). The
// `T...` suffix is dropped before parsing so the pandas `df_to_sheet` helper
// — which uses `df.to_json(orient="split", date_format="iso")` and therefore
// always emits the full ISO form — round-trips without an extra string clean
// step on the agent side. A leading `T` (no date prefix) is left alone so the
// parser still rejects it cleanly.
func isoDateToSerial(s string) (float64, error) {
	s = strings.TrimSpace(s)
	if s == "" {
		// Empty cells in a date-typed column are the classic header/total-row
		// clash with the column-wide dtype declaration; name the three ways
		// out so the caller does not have to guess what "bad format" means.
		return 0, fmt.Errorf("date column has an empty cell — drop the empty rows, fill real yyyy-mm-dd dates, or declare the column dtype as object (text)") //nolint:forbidigo // intermediate error; callers wrap it into a typed --sheets/--values validation error with row/column context
	}
	if i := strings.Index(s, "T"); i > 0 {
		base := s[:i]
		date, err := time.Parse("2006-01-02", base)
		if err != nil {
			return 0, fmt.Errorf("date %q must be ISO yyyy-mm-dd: %w", base, err) //nolint:forbidigo // intermediate parse error; caller wraps it with typed validation context
		}
		var parsed time.Time
		clock := s[i:]
		if strings.ContainsAny(clock, "Zz+-") {
			parsed, err = time.Parse(time.RFC3339Nano, s)
		} else {
			parsed, err = time.Parse("2006-01-02T15:04:05.999999999", s)
		}
		if err != nil {
			return 0, fmt.Errorf("datetime %q must be ISO: %w", s, err) //nolint:forbidigo // intermediate parse error; caller wraps it with typed validation context
		}
		if parsed.Location() != time.UTC {
			// Keep the wall-clock time supplied by the caller; Excel serials do
			// not carry a timezone and table-put historically treated the ISO
			// date/time as the sheet-local value.
			return date.Sub(excelEpoch).Hours()/24 + float64(parsed.Hour()*3600+parsed.Minute()*60+parsed.Second())/86400 + float64(parsed.Nanosecond())/(86400*1e9), nil
		}
		return date.Sub(excelEpoch).Hours()/24 + float64(parsed.Hour()*3600+parsed.Minute()*60+parsed.Second())/86400 + float64(parsed.Nanosecond())/(86400*1e9), nil

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Reformat the value to strict yyyy-mm-dd before the T, e.g. "2026-01-31T10:00:00"
  2. Zero-pad month and day (01-05 not 1-5)
  3. If the column holds non-ISO text, change its dtype to "object"

Example fix

// before
{"name":"Due","type":"date","data":["31/01/2026T10:00"]}
// after
{"name":"Due","type":"date","data":["2026-01-31T10:00:00"]}
Defensive patterns

Strategy: validation

Validate before calling

function assertISOBasedate(v) {
  const i = v.indexOf('T');
  if (i > 0 && isNaN(Date.parse(v.slice(0, i) + 'T00:00:00Z')))
    throw new Error(`base date '${v.slice(0, i)}' is not yyyy-mm-dd`);
}

Type guard

function hasValidISOBaseDate(v) { const m = /^(\d{4}-\d{2}-\d{2})T/.exec(v); return !!m && !isNaN(Date.parse(m[1] + 'T00:00:00Z')); }

Try / catch

try {
  await run(['lark','sheet','table-put','--sheets',payload]);
} catch (e) {
  if (/must be ISO yyyy-mm-dd/.test(e.message)) {
    // reformat the pre-T part to yyyy-mm-dd and retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Date column value like "31/01/2026T10:00", "2026-1-5T09:00:00", or "2026-13-01T00:00" — the part before 'T' is not a valid yyyy-mm-dd date.

Common situations: US-style or locale-formatted dates pasted from other tools; single-digit month/day without zero padding; upstream systems emitting local formats.

Related errors


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