{"record":{"id":"62484003138e0e90","repo":"larksuite/cli","slug":"date-column-has-an-empty-cell-drop-the-empty-row","errorCode":null,"errorMessage":"date column has an empty cell — drop the empty rows, fill real yyyy-mm-dd dates, or declare the column dtype as object (text)","messagePattern":"date column has an empty cell — drop the empty rows, fill real yyyy-mm-dd dates, or declare the column dtype as object \\(text\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shortcuts/sheets/lark_sheet_table_io.go","lineNumber":775,"sourceCode":"\n// isoDateToSerial converts an ISO yyyy-mm-dd string to its Excel serial day\n// number. A time suffix is retained as a fractional day so table-get/table-put\n// round-trips datetime-formatted cells without dropping the clock component.\n//\n// Accepts both bare dates (`2024-01-15`) and full ISO datetime strings with a\n// `T` separator (`2024-01-15T00:00:00.000`, `2024-01-15T08:30:00+08:00`). The\n// `T...` suffix is dropped before parsing so the pandas `df_to_sheet` helper\n// — which uses `df.to_json(orient=\"split\", date_format=\"iso\")` and therefore\n// always emits the full ISO form — round-trips without an extra string clean\n// step on the agent side. A leading `T` (no date prefix) is left alone so the\n// parser still rejects it cleanly.\nfunc isoDateToSerial(s string) (float64, error) {\n\ts = strings.TrimSpace(s)\n\tif s == \"\" {\n\t\t// Empty cells in a date-typed column are the classic header/total-row\n\t\t// clash with the column-wide dtype declaration; name the three ways\n\t\t// out so the caller does not have to guess what \"bad format\" means.\n\t\treturn 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\n\t}\n\tif i := strings.Index(s, \"T\"); i > 0 {\n\t\tbase := s[:i]\n\t\tdate, err := time.Parse(\"2006-01-02\", base)\n\t\tif err != nil {\n\t\t\treturn 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\n\t\t}\n\t\tvar parsed time.Time\n\t\tclock := s[i:]\n\t\tif strings.ContainsAny(clock, \"Zz+-\") {\n\t\t\tparsed, err = time.Parse(time.RFC3339Nano, s)\n\t\t} else {\n\t\t\tparsed, err = time.Parse(\"2006-01-02T15:04:05.999999999\", s)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn 0, fmt.Errorf(\"datetime %q must be ISO: %w\", s, err) //nolint:forbidigo // intermediate parse error; caller wraps it with typed validation context\n\t\t}\n\t\tif parsed.Location() != time.UTC {","sourceCodeStart":757,"sourceCodeEnd":793,"githubUrl":"https://github.com/larksuite/cli/blob/7fd6ef3c07182257ce776cdc5a614e122d5bd4b3/shortcuts/sheets/lark_sheet_table_io.go#L757-L793","documentation":"isoDateToSerial converts a date column's string into an Excel serial number. An empty (or whitespace-only) cell in a date-typed column cannot be converted, so this prescriptive error names the three ways out: drop the empty rows, provide real dates, or change the column dtype to object/text. Callers add row/column context.","triggerScenarios":"A --sheets/--values payload with a date column containing \"\" or \"   \" in any row — typically a totals row, blank separator row, or partially filled table.","commonSituations":"Header/total rows that leave the date cell blank; CSV exports with empty trailing cells; sparse data where some records have no date yet.","solutions":["Fill the empty cells with real yyyy-mm-dd dates (e.g. \"2026-01-31\")","Remove the empty rows from the payload before putting","Declare the column dtype as \"object\" (text) so blanks are stored as literal text"],"exampleFix":"// before\n{\"name\":\"Due\",\"type\":\"date\",\"data\":[\"2026-01-31\",\"\"]}\n// after\n{\"name\":\"Due\",\"type\":\"date\",\"data\":[\"2026-01-31\",\"2026-02-01\"]}\n// or dtype\n{\"name\":\"Due\",\"type\":\"object\",\"data\":[\"2026-01-31\",\"\"]}","handlingStrategy":"validation","validationCode":"function assertNoEmptyDates(col) {\n  col.data.forEach((v, i) => {\n    if (typeof v === 'string' && v.trim() === '')\n      throw new Error(`column ${col.name} (date): row ${i} is empty; fill a yyyy-mm-dd date or use dtype object`);\n  });\n}","typeGuard":"function isFilledDate(v) { return typeof v === 'string' && v.trim() !== ''; }","tryCatchPattern":"try {\n  await run(['lark','sheet','table-put','--sheets',payload]);\n} catch (e) {\n  if (/date column has an empty cell/.test(e.message)) {\n    // drop empty rows, fill dates, or change dtype to \"object\" and retry\n  }\n  throw e;\n}","preventionTips":["Strip blank separator/totals rows from tabular data before put","Pre-decide the policy for missing dates (fill sentinel, omit row, or text dtype)","Validate payloads row-by-row before invoking the CLI"],"tags":["cli","validation","sheets","date"],"backgroundTag":"empty-date-cell","analyzedSha":"7fd6ef3c07182257ce776cdc5a614e122d5bd4b3","analyzedAt":"2026-09-04T21:17:44.649Z","contentChangedAt":"2026-09-04T21:17:44.649Z","schemaVersion":2},"datasetVersion":"2026-09-12T02:17:10.037Z"}