fix(smartsheet): handle POST /rows response as either object or array
Deploy to route.crispygoat.com / deploy (push) Successful in 4m5s

Smartsheet's POST /sheets/{id}/rows response shape varies by request size:
  - Single-row request → result: { id, rowNumber, ... }   (object)
  - Multi-row request  → result: [{ id, rowNumber, ... }] (array)

We always post exactly one row, so the actual response is the object
form. The previous fix (b061cdd) assumed the array form, so
data.result[0] was undefined for object responses, and addRow threw
a 502 'returned no row' AFTER Smartsheet had successfully created
the row. The queue then recorded a failed sync attempt even though
the data was sitting in the sheet.

User saw this in Recent Activity: 10 sequential retries with
'Smartsheet 502: returned no row' errors but incrementing rowNumber
in the response body (21 → 30), proving the rows were being created
on Smartsheet's side and our parser was the only thing failing.

Fix: check Array.isArray(result) and use result[0] for the array form,
or result directly for the object form. Belt-and-suspenders for both
shapes since Smartsheet's docs are ambiguous about the single-row case.

Side note: the failed attempts did create rows on Smartsheet. Once
the fix deploys, retries will hit findRowByColumn first, which will
locate those existing rows by Entry ID and skip the duplicate insert.
Net result: 25 unique rows in the sheet, queue marked synced.
This commit is contained in:
Nora
2026-07-03 16:53:49 -06:00
parent 928779e06d
commit 5aab432e5a
+11 -6
View File
@@ -279,12 +279,16 @@ export async function addRow(
return v; return v;
}; };
// NOTE: POST /2.0/sheets/{id}/rows wraps the created row(s) in // NOTE: POST /2.0/sheets/{id}/rows response shape varies:
// `{ result: [{id, rowNumber}, ...] }` — different shape from the // - One row in request → result: { id, rowNumber, ... } (single object)
// flat GET /2.0/sheets/{id} response. See // - Multiple rows → result: [{ id, rowNumber, ... }, ...] (array)
// https://smartsheet.redoc.ly/#operation/addRows // We always post exactly one row, but handle both defensively. Different
// from the flat GET /2.0/sheets/{id} response.
// See https://smartsheet.redoc.ly/#operation/addRows
type ApiResponse = { type ApiResponse = {
result: Array<{ id: number; rowNumber: number }>; result:
| { id: number; rowNumber: number; [k: string]: unknown }
| Array<{ id: number; rowNumber: number; [k: string]: unknown }>;
resultCode?: number; resultCode?: number;
message?: string; message?: string;
}; };
@@ -305,7 +309,8 @@ export async function addRow(
}, },
); );
const row = data?.result?.[0]; const result = data?.result;
const row = Array.isArray(result) ? result[0] : result;
if (!row || row.id == null) { if (!row || row.id == null) {
throw new SmartsheetApiError( throw new SmartsheetApiError(
502, 502,