thedotmack/claude-mem · warning

[claude-mem] Failed to parse search results:

Error message

[claude-mem] Failed to parse search results:

What it means

A console.warn from the opencode plugin's parseSearchResponse: the worker's HTTP response body could not be JSON.parse'd at all. The plugin expects the worker's Claude-style { content: [{ type:'text', text }] } envelope; when the body is an HTML error page, a proxy message, or an empty/truncated response, parsing throws and the function degrades to a user-facing 'Failed to parse search results.' string.

Source

Thrown at src/integrations/opencode-plugin/index.ts:315

          return parseSearchResponse(text, query);
        },
      },
    },
  };
};

/**
 * The worker returns Claude-style `{ content: [{ type: 'text', text: '...' }] }`
 * blocks, NOT `{ items: [...] }` (#2406). Concatenate the text blocks and return
 * them verbatim; an empty block list or a "No observations found" body becomes a
 * clear no-results message.
 */
export function parseSearchResponse(text: string, query: string): string {
  let data: unknown;
  try {
    data = JSON.parse(text);
  } catch (error: unknown) {
    console.warn(
      "[claude-mem] Failed to parse search results:",
      error instanceof Error ? error.message : String(error),
    );
    return "Failed to parse search results.";
  }

  const content = (data as { content?: Array<{ type?: string; text?: string }> }).content;
  if (!Array.isArray(content) || content.length === 0) {
    return `No results found for "${query}".`;
  }

  const rendered = content
    .filter((block) => block.type === "text" && typeof block.text === "string")
    .map((block) => block.text as string)
    .join("\n")
    .trim();

  if (!rendered) {

View on GitHub (pinned to e2d1df569a)

Solutions

  1. Verify the configured worker URL answers JSON: curl -s <base>/api/health
  2. Match plugin and worker versions — the content-block response shape is version-dependent (#2406)
  3. Log the raw text before parsing to see what actually came back, then fix the routing/port mismatch

Example fix

// before
const data = JSON.parse(text); // throws on HTML 404 page

// after
let data: unknown;
try {
  data = JSON.parse(text);
} catch {
  console.error('non-JSON worker response:', text.slice(0, 200));
  return `Search unavailable (worker returned non-JSON).`;
}
Defensive patterns

Strategy: fallback

Validate before calling

function looksLikeWorkerJson(text: string): boolean {
  const t = text.trimStart();
  return t.startsWith('{') || t.startsWith('[');
}

Type guard

interface SearchEnvelope { content?: Array<{ type?: string; text?: string }> }
function isSearchEnvelope(data: unknown): data is SearchEnvelope {
  return typeof data === 'object' && data !== null &&
    Array.isArray((data as SearchEnvelope).content);
}

Try / catch

let data: unknown;
try { data = JSON.parse(text); }
catch { return 'Search unavailable (worker returned non-JSON response).'; }
if (!isSearchEnvelope(data) || data.content.length === 0)
  return `No results found for "${query}".`;

Prevention

When it happens

Trigger: The opencode tool points at a wrong port/host where something else answers (returning HTML); a reverse proxy or captive portal intercepts the request; the response is chunk-truncated by a timeout; the worker URL includes a path prefix that 404s with an HTML body.

Common situations: CLAUDE_MEM_WORKER_PORT changed after the plugin was configured; plugin version expecting the #2406 content-block shape against an older worker returning { items: [...] }-style or plain text; localhost firewall/AV middleware injecting error pages.

Understand the failure class

Related errors


AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20). Data as JSON: /api/errors/697164a53e7f32b1. Report an issue: GitHub.