{"record":{"id":"1ad7745a435772d6","repo":"jackwener/OpenCLI","slug":"flomo-api-returned-malformed-memo-data","errorCode":null,"errorMessage":"Flomo API returned malformed memo data","messagePattern":"Flomo API returned malformed memo data","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/flomo/memos.js","lineNumber":212,"sourceCode":"  func: async (page, kwargs) => {\n    const limit = parsePositiveIntArg(kwargs.limit, 'limit', 20, MAX_LIMIT);\n    const since = parseSinceArg(kwargs.since);\n    const slug = parseSlugArg(kwargs.slug);\n    await page.wait(3).catch(() => {});\n    const token = await readAccessToken(page);\n    const body = await fetchFlomoJson(buildSignedUrl(limit, since, slug), token);\n    if (!body || typeof body !== 'object' || Array.isArray(body)) {\n      throw new CommandExecutionError('Flomo API returned a malformed response');\n    }\n    if (body.code !== 0) {\n      const message = body.message || `Flomo API error code ${body.code}`;\n      if (isAuthFailureMessage(message)) {\n        throw new AuthRequiredError(FLOMO_API_DOMAIN, message);\n      }\n      throw new CommandExecutionError(message);\n    }\n    if (!Array.isArray(body.data)) {\n      throw new CommandExecutionError('Flomo API returned malformed memo data');\n    }\n    if (body.data.length === 0) {\n      throw new EmptyResultError('flomo memos', 'No Flomo memos matched the requested filters.');\n    }\n    return body.data.map(normalizeMemo);\n  },\n});\n\nexport const __test__ = {\n  buildSignedUrl,\n  command,\n  normalizeMemo,\n  parsePositiveIntArg,\n  parseSinceArg,\n  parseSlugArg,\n};\n","sourceCodeStart":194,"sourceCodeEnd":229,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/flomo/memos.js#L194-L229","documentation":"clis/flomo/memos.js throws this CommandExecutionError after a Flomo API response arrives but its `data` field is not an array. The memos command expects the envelope `{ data: [...] }`; any other shape means the API contract changed or the response is not memo data. It guards downstream `body.data.map(normalizeMemo)` from crashing on a non-array.","triggerScenarios":"The Flomo API returns 200 with a body where `data` is missing, an object, a string, or null — e.g. a changed response schema, an HTML/JSON error page parsed into `{}`, or an unexpected payload from the memos endpoint.","commonSituations":"Flomo changes its private/API response shape; a proxy or captive portal returns HTML; the request hits a login page instead of memo JSON; stale session produces an empty object body that passes auth checks.","solutions":["Re-run the command with a valid, fresh Flomo session/auth to rule out a redirected login response","Inspect the raw response body (log `body` before validation) to see what shape actually arrived","Update opencli/flomo CLI to a version matching the current Flomo API response format","If Flomo changed its schema, patch the parsing code so `body.data` matches the new envelope"],"exampleFix":"// before\nif (!Array.isArray(body.data)) {\n  throw new CommandExecutionError('Flomo API returned malformed memo data');\n}\n// after\nconst data = Array.isArray(body?.data) ? body.data : Array.isArray(body) ? body : null;\nif (!data) {\n  throw new CommandExecutionError(`Flomo API returned malformed memo data: ${JSON.stringify(body).slice(0, 200)}`);\n}","handlingStrategy":"type-guard","validationCode":"if (!apiResponse || !Array.isArray(apiResponse.data)) {\n  throw new Error('Flomo response missing data array; aborting before map()');\n}","typeGuard":"function hasMemoData(body) {\n  return typeof body === 'object' && body !== null && Array.isArray(body.data);\n}","tryCatchPattern":"try {\n  const memos = await flomoMemos(filters);\n} catch (err) {\n  if (err.message.includes('malformed memo data')) {\n    logRawResponseForDebugging(); // inspect actual body shape / re-auth\n  } else {\n    throw err;\n  }\n}","preventionTips":["Keep the CLI updated against Flomo API changes","Log the raw response body on parse failures for diagnosis","Check for login-redirect HTML before JSON parsing","Verify session validity before calling the memos endpoint"],"tags":["api","response-validation","flomo"],"backgroundTag":"api-response-schema-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}