jackwener/OpenCLI · error · CommandExecutionError
expected files array, got ${typeof files} (contract drift?)
Error message
expected files array, got ${typeof files} (contract drift?) What it means
After evaluating the in-page fetch snippet, `channel-files` normalizes the result to a `files` array and throws CommandExecutionError if the result is neither an array nor an object with a `files` array. The '(contract drift?)' note flags that Slock's response shape changed from what the CLI expects.
Source
Thrown at clis/slock/channel-files.js:40
],
columns: ['id', 'filename', 'mimeType', 'sizeBytes', 'messageId', 'createdAt'],
func: async (page, kwargs) => {
const channel = String(kwargs.channel ?? '').trim();
if (!channel) throw new ArgumentError('channel required');
const limit = parsePositiveInteger(kwargs.limit, '--limit', { defaultValue: 50 });
await page.goto(SLOCK_HOME_URL);
const snippet = buildChannelScopedSnippet({
channelInput: channel,
method: 'GET',
pathSuffix: '/files',
query: `?limit=${limit}`,
serverIdOverride: kwargs.server,
});
const result = await page.evaluate(`(async () => { ${snippet} })()`);
const data = dispatchEvaluateResult(result);
const files = Array.isArray(data) ? data : (data.files || []);
if (!Array.isArray(files)) {
throw new CommandExecutionError(`expected files array, got ${typeof files} (contract drift?)`);
}
return files.map((f) => ({
id: f.id ?? '',
filename: f.filename ?? '',
mimeType: f.mimeType ?? '',
sizeBytes: typeof f.sizeBytes === 'number' ? f.sizeBytes : null,
messageId: f.messageId ?? '',
createdAt: f.createdAt ?? '',
}));
},
});
View on GitHub (pinned to 49907e53dc)
Solutions
- Re-authenticate / refresh the session in the Slock app, then retry
- Update the slock CLI package to the latest version matching the current Slock app contract
- Log the raw result (rerun with debug output) and inspect the actual response shape
- File/check an issue against the CLI if the Slock API changed its files payload
Example fix
// before (in CLI) const files = Array.isArray(data) ? data : (data.files || []); // after (defensive) const files = Array.isArray(data) ? data : (Array.isArray(data.files) ? data.files : Array.isArray(data.data?.files) ? data.data.files : []);
Defensive patterns
Strategy: type-guard
Validate before calling
// cannot be validated pre-call; inspect raw output when debugging // rerun with debug logging to capture the raw page.evaluate result shape
Type guard
const isFilesPayload = (d) => Array.isArray(d) || (d && typeof d === 'object' && Array.isArray(d.files));
Try / catch
try {
const files = await slock.channelFiles({ channel: '#ops' });
} catch (e) {
if (e instanceof CommandExecutionError && /contract drift/.test(e.message)) {
// refresh session, then upgrade the CLI to match the current Slock contract
await refreshSession();
return retryWithUpdatedCli();
}
throw e;
} Prevention
- Keep the CLI version in sync with the Slock app version
- Refresh the Slock session when payloads start looking like HTML/login pages
- Pin and test CLI integrations against Slock updates; subscribe to changelogs
When it happens
Trigger: The evaluated snippet returns an object without a `files` array — e.g. Slock returns `{ data: {...} }`, an error envelope, or an HTML/login page parsed as an object instead of the expected `{ files: [...] }` or plain array.
Common situations: Slock app update changing the files endpoint response shape, session expiry causing the snippet to receive an auth redirect body, or a server returning an error object the CLI's `dispatchEvaluateResult` passes through.
Related errors
- expected array of rows from server, got ${typeof rows} (cont
- 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/f8716a7db36eea36.
Report an issue: GitHub.