OpenHands/OpenHands · error · Error

Invalid conversation history response: expected page.items t

Error message

Invalid conversation history response: expected page.items to be an array.

What it means

Defensive guard inside useConversationHistory's queryFn: after EventService.searchEvents returns a page, the code asserts Array.isArray(page.items) before reversing. The agent-server contract is an EventSearchPage with an items array; a non-array means the response was malformed (wrong shape, null, or a cloud-proxy error envelope). Rather than crashing on .reverse() of undefined, the hook throws an explicit, grep-able error so React Query surfaces a failure.

Source

Thrown at src/hooks/query/use-conversation-history.ts:59

    ],
    enabled: !!conversationId && !!conversation,
    queryFn: async () => {
      if (!conversationId) {
        return { events: [], hasMore: false, nextPageId: null };
      }

      const page = await EventService.searchEvents(
        conversationId,
        conversation?.conversation_url ?? null,
        conversation?.session_api_key ?? null,
        {
          limit: INITIAL_HISTORY_PAGE_SIZE,
          sortOrder: "TIMESTAMP_DESC",
        },
      );

      if (!Array.isArray(page.items)) {
        throw new Error(
          "Invalid conversation history response: expected page.items to be an array.",
        );
      }

      // Reverse so callers can append in chronological order.
      const events = [...page.items].reverse();
      return {
        events,
        hasMore:
          !!page.next_page_id || page.items.length >= INITIAL_HISTORY_PAGE_SIZE,
        nextPageId: page.next_page_id ?? null,
      };
    },
    // Keep the cached page so returning to a conversation renders the
    // last-known discussion instantly (no skeleton). But refetch the tail on
    // mount so events produced while we were away — e.g. an active /goal loop
    // that keeps emitting user + agent turns while we're on another
    // conversation — arrive in one batched REST page instead of being

View on GitHub (pinned to 500b4c533e)

Solutions

  1. Check the actual response body of GET /api/conversations/{id}/events in the browser network tab — confirm `items` exists and is an array.
  2. Verify the agent-server version satisfies compatibility.minimumAgentServer in config/defaults.json (assertAgentServerVersionIsSupported runs on bootstrap, not here, so a bypassed check is possible).
  3. If a custom ingress/proxy is in front of the agent-server, ensure it passes JSON bodies through unmodified.
  4. On the cloud path, confirm callCloudProxy unwraps error envelopes before they reach EventService.searchEvents.
Defensive patterns

Strategy: type-guard

Validate before calling

function isEventSearchPage(value: unknown): value is { items: unknown[]; next_page_id?: string | null } {
  return typeof value === 'object' && value !== null && Array.isArray((value as any).items);
}
// const page = await EventService.searchEvents(...);
// if (!isEventSearchPage(page)) return { events: [], hasMore: false, nextPageId: null };

Type guard

function isValidHistoryPage(page: unknown): page is { items: import('#/types/agent-server/core').OpenHandsEvent[]; next_page_id?: string | null } {
  return !!page && typeof page === 'object' && Array.isArray((page as { items?: unknown }).items);
}

Prevention

When it happens

Trigger: Initial REST history fetch (sort_order=TIMESTAMP_DESC, limit=50) returns a payload whose `items` field is not an array. Happens when: the cloud proxy returns an error object instead of a page; the agent-server returns a legacy/different shape after an upgrade; a middleware (ingress/proxy) rewrites the body; the response is an empty `null`.

Common situations: Agent-server version mismatch (frontend expects the new EventSearchPage shape); cloud proxy returning a 4xx/5xx error envelope that was not unwrapped; ingress returning its own error JSON; custom reverse proxy stripping the items field; response truncated by a body-size limit.

Related errors


AI-assisted analysis of OpenHands/OpenHands@500b4c533e (2026-08-12). Data as JSON: /api/errors/7bc98080a589b4e7. Report an issue: GitHub.