{"record":{"id":"96949f535211593b","repo":"linshenkx/prompt-optimizer","slug":"garden-suggestions-response-must-be-an-object","errorCode":null,"errorMessage":"Garden suggestions response must be an object","messagePattern":"Garden suggestions response must be an object","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/ui/src/utils/prompt-garden-suggestions.ts","lineNumber":170,"sourceCode":"  const controller = new AbortController()\n  const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? DEFAULT_TIMEOUT_MS)\n\n  try {\n    const resp = await fetch(url, {\n      method: 'GET',\n      headers: {\n        Accept: 'application/json',\n      },\n      signal: controller.signal,\n    })\n\n    if (!resp.ok) {\n      throw new Error(`Garden suggestions request failed: ${resp.status}`)\n    }\n\n    const data = (await resp.json()) as unknown\n    if (!isRecord(data)) {\n      throw new Error('Garden suggestions response must be an object')\n    }\n\n    const items = Array.isArray(data.items)\n      ? data.items\n          .map((item) => normalizeSuggestionItem(item, gardenBaseUrl))\n          .filter((item): item is PromptGardenSuggestionItem => Boolean(item))\n      : []\n\n    const browseUrl =\n      resolveGardenUrl(gardenBaseUrl, data.browseUrl) ||\n      buildFallbackBrowseUrl(gardenBaseUrl, options.mode)\n\n    const ttlSeconds =\n      typeof data.ttlSeconds === 'number' && Number.isFinite(data.ttlSeconds) && data.ttlSeconds > 0\n        ? Math.floor(data.ttlSeconds)\n        : null\n\n    return {","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/linshenkx/prompt-optimizer/blob/3e677b1d9f7e0493c142c175560531e7ae786dce/packages/ui/src/utils/prompt-garden-suggestions.ts#L152-L188","documentation":"Thrown by fetchPromptGardenSuggestions when the suggestions endpoint returns HTTP 200 but the JSON body is not an object (e.g. an array, string, number, or null). The library parses the body and runs an isRecord check before reading data.items; any non-object payload fails fast with this error instead of producing a TypeError later.","triggerScenarios":"Endpoint returns a JSON array, bare string/number, or null body; a proxy or gateway returning a JSON-encoded error string with 200; misrouted endpoint returning a different JSON shape.","commonSituations":"API version mismatch where the deployed garden returns a list instead of { items: [...] }; middleware or CDN intercepting and rewriting responses; backend returning null for an empty result set.","solutions":["Inspect the actual response body (curl the endpoint) to see the real shape","Upgrade/align the garden service and client versions so the response is { items: [...] }","Fix backend serialization to always return an object with items (possibly empty array)","Remove any proxy/rewrite rules that transform the response body"],"exampleFix":"// backend: return an object with items instead of a bare array\n// before\nreturn NextResponse.json(suggestions) // e.g. [{...}, {...}]\n// after\nreturn NextResponse.json({ items: suggestions })","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"const isSuggestionsResponse = (data: unknown): data is { items: unknown[] } =>\n  typeof data === 'object' && data !== null && Array.isArray((data as { items?: unknown }).items)","tryCatchPattern":"try {\n  const items = await fetchPromptGardenSuggestions(options)\n} catch (error) {\n  if ((error as Error).message.includes('must be an object')) {\n    // endpoint/shape mismatch: log payload, fall back to empty suggestions\n    return []\n  }\n  throw error\n}","preventionTips":["Contract-test the endpoint shape in CI against the deployed garden service","Version the API and pin client/server versions together","Treat shape errors as non-retryable bugs, not transient failures"],"tags":["response-validation","json-shape","prompt-garden"],"backgroundTag":"invalid-response-schema","analyzedSha":"3e677b1d9f7e0493c142c175560531e7ae786dce","analyzedAt":"2026-08-27T21:29:16.709Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}