jackwener/OpenCLI · error · CommandExecutionError
expected array of rows from server, got ${typeof rows} (cont
Error message
expected array of rows from server, got ${typeof rows} (contract drift?) What it means
After evaluating the server-scoped fetch snippet, `channel-list` expects `dispatchEvaluateResult` to return an array of channel rows and throws CommandExecutionError otherwise. '(contract drift?)' signals the server/CLI response contract changed — e.g. the endpoint now returns `{ channels: [...] }` or an error object.
Source
Thrown at clis/slock/channel-list.js:32
strategy: Strategy.COOKIE,
browser: true,
siteSession: 'persistent',
args: [
{ name: 'server', help: 'Override active server (slug or id) for this call' },
],
columns: ['id', 'name', 'topic'],
func: async (page, kwargs) => {
await page.goto(SLOCK_HOME_URL);
const snippet = buildFetchSnippet({
method: 'GET',
path: '/channels/',
serverScoped: true,
serverIdOverride: kwargs.server,
});
const result = await page.evaluate(`(async () => { ${snippet} })()`);
const rows = dispatchEvaluateResult(result);
if (!Array.isArray(rows)) {
throw new CommandExecutionError(`expected array of rows from server, got ${typeof rows} (contract drift?)`);
}
return rows.map((c) => ({
id: c.id ?? '',
name: c.name ?? c.slug ?? '',
topic: c.topic ?? '',
}));
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Re-authenticate in the Slock app / refresh session and retry
- Update the slock CLI to the version matching the current Slock app
- Inspect the raw evaluate result with debug output to see the actual shape
- Patch normalization locally (e.g. unwrap `data.channels`) and report upstream
Example fix
// before (in CLI) const rows = dispatchEvaluateResult(result); if (!Array.isArray(rows)) throw new CommandExecutionError(...); // after (defensive unwrap) let rows = dispatchEvaluateResult(result); if (!Array.isArray(rows) && Array.isArray(rows?.channels)) rows = rows.channels;
Defensive patterns
Strategy: type-guard
Validate before calling
// cannot be validated pre-call; capture the raw response when debugging // add debug logging around page.evaluate to see what the server returned
Type guard
const isRowsPayload = (d) => Array.isArray(d) || (d && typeof d === 'object' && Array.isArray(d.channels));
Try / catch
try {
const channels = await slock.channelList();
} catch (e) {
if (e instanceof CommandExecutionError && /contract drift/.test(e.message)) {
await refreshSession();
return retryWithUpdatedCli();
}
throw e;
} Prevention
- Keep the CLI updated alongside Slock app changes
- Re-authenticate when responses look like login/redirect payloads
- Add contract tests that assert channelList returns an array
When it happens
Trigger: The evaluated snippet returns a non-array — Slock returns a wrapped object (`{ channels: [...] }`, `{ data: [...] }`), an auth/login HTML payload, or an error envelope the CLI doesn't unwrap.
Common situations: Slock app update altering the channels endpoint shape, expired session causing a redirect/error body, or using an old CLI against a newer Slock instance.
Related errors
- expected files array, got ${typeof files} (contract drift?)
- expected inbox items array, got ${typeof items} (contract dr
- expected array of rows from server, got ${typeof list} (cont
- expected array of rows from server, got ${typeof rows} (cont
- workspace/create returned no workspace_id: ${JSON.stringify(
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/c40e9aa32bd3114a.
Report an issue: GitHub.