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

message-search.js expects the normalized evaluate result to be an array of message rows which it then maps to output columns. If dispatchEvaluateResult returns a non-array it throws this CommandExecutionError, signaling the server response no longer matches the CLI's expected contract (the snippet itself already coerces bare arrays or objects with results/messages/data).

Source

Thrown at clis/slock/message-search.js:62

          const arr = await cres.json();
          const hit = (Array.isArray(arr)?arr:(arr.channels||arr.data||[])).find((c) => (c.name||c.slug||'').toLowerCase() === ${target});
          if (!hit) return { kind: 'unresolvable', detail: 'no channel matches ' + ${JSON.stringify(channel)} };
          channelId = hit.id;
        }
      }
      const searchUrl = '${SLOCK_API_BASE}/messages/search?q=' + encodeURIComponent(${JSON.stringify(q)}) + (channelId ? '&channelId=' + encodeURIComponent(channelId) : '') + '&limit=' + encodeURIComponent(${JSON.stringify(limit)});
      const res = await fetch(searchUrl, { credentials:'include', headers });
      if (!res.ok) return { kind: res.status===401?'auth':'http', status: res.status, where:'/messages/search' };
      const data = await res.json();
      // F2-b — qatester live dump: shape is { results: [...], hasMore }.
      // Unwrap .results first; fall back to legacy .messages / .data /
      // bare array for forward-compat.
      return { kind: 'ok', rows: Array.isArray(data) ? data : (data.results || data.messages || data.data || []) };
    `;
    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((m) => ({
      id: m.id ?? m.messageId ?? '',
      channelId: m.channelId ?? '',
      createdAt: m.createdAt ?? m.created_at ?? '',
      senderName: m.sender?.name ?? m.user?.name ?? '',
      content: m.content ?? '',
    }));
  },
});

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Extend the fallback chain in the snippet's return line to include the new field name (e.g. data.hits || data.matches).
  2. Log `result`/`rows` before the throw to see the actual envelope.
  3. Verify auth and active server so the search endpoint returns real rows.
  4. Update the CLI to match the current server search contract.

Example fix

// before
return { kind: 'ok', rows: Array.isArray(data) ? data : (data.results || data.messages || data.data || []) };
// after
return { kind: 'ok', rows: Array.isArray(data) ? data : (data.results || data.messages || data.data || data.hits || []) };
Defensive patterns

Strategy: type-guard

Validate before calling

const rows = dispatchEvaluateResult(result);
if (!Array.isArray(rows)) throw new Error(`unexpected search payload: ${JSON.stringify(rows).slice(0,200)}`);

Type guard

function isSearchRows(v) { return Array.isArray(v); }

Try / catch

try { const rows = await searchMessages(page, kwargs); } catch (e) { if (String(e.message).includes('expected array of rows from server')) { console.error('Search response contract drift — check envelope field names'); } else throw e; }

Prevention

When it happens

Trigger: The endpoint returns an envelope field the snippet doesn't know (e.g. `hits`, `matches`); an auth/error object passes through dispatchEvaluateResult as a non-array; the snippet returns {kind:'error'} shape unexpectedly.

Common situations: Server API upgrade renaming the results field; proxy injecting error bodies; degraded mode returning metadata instead of rows.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/9efc39b7ec755c9d. Report an issue: GitHub.