{"record":{"id":"e91e68ffa3d7d9e7","repo":"jackwener/OpenCLI","slug":"linkedin-post-analytics-expected-an-array-of-posts","errorCode":null,"errorMessage":"LinkedIn post analytics expected an array of posts","messagePattern":"LinkedIn post analytics expected an array of posts","errorType":"error_code","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/post-analytics.js","lineNumber":15,"sourceCode":"import { cli, Strategy } from '@jackwener/opencli/registry';\nimport { CommandExecutionError, EmptyResultError } from '@jackwener/opencli/errors';\nimport { parseLimit } from './shared.js';\nimport { collectPosts } from './posts-core.js';\n\nconst DEFAULT_LIMIT = 30;\nconst MAX_LIMIT = 100;\n\nfunction sum(posts, field) {\n  return posts.reduce((total, post) => total + (Number(post[field]) || 0), 0);\n}\n\nfunction summarize(posts) {\n  if (!Array.isArray(posts)) {\n    throw new CommandExecutionError('LinkedIn post analytics expected an array of posts');\n  }\n  if (posts.length === 0) {\n    throw new EmptyResultError('linkedin post-analytics', 'No posts were available for analytics.');\n  }\n  const latest = posts[0] || {};\n  return {\n    posts_analyzed: posts.length,\n    total_reactions: sum(posts, 'reactions'),\n    total_comments: sum(posts, 'comments'),\n    total_reposts: sum(posts, 'reposts'),\n    total_impressions: sum(posts, 'impressions'),\n    posts_with_media: posts.filter((post) => post.media).length,\n    posts_with_urls: posts.filter((post) => post.url).length,\n    latest_posted_at: latest.posted_at || '',\n    latest_reactions: Number(latest.reactions) || 0,\n    latest_comments: Number(latest.comments) || 0,\n    latest_reposts: Number(latest.reposts) || 0,\n    latest_impressions: Number(latest.impressions) || 0,","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/post-analytics.js#L1-L33","documentation":"This CommandExecutionError is thrown by summarize() in post-analytics when the posts argument is not an array. The analytics pipeline expects an array of post objects to aggregate; anything else (null, undefined, an object) is treated as a malformed input rather than an empty result.","triggerScenarios":"Calling the post-analytics command (via out/summarize) when the upstream fetch produced a non-array value — e.g. the posts extraction returned undefined/null because the page had no posts container, or a refactor passed a single post object instead of an array.","commonSituations":"Scraping a profile with zero posts where the extractor returns null instead of []; API/DOM change turning the posts payload into an object wrapper; caller mistakenly passes one post object rather than an array.","solutions":["Ensure the posts extraction step always returns an array (default to [] when nothing found)","Pass an array to post-analytics, wrapping single posts in [post]","Check whether a LinkedIn DOM/API change made the extractor return a non-array and update the library","Log the actual value passed to summarize to identify the upstream source of the non-array"],"exampleFix":"// before\nsummarize(postsPayload); // postsPayload may be null\n// after\nsummarize(Array.isArray(postsPayload) ? postsPayload : []);","handlingStrategy":"type-guard","validationCode":"const posts = await collectPosts();\nif (!Array.isArray(posts)) throw new Error('posts extractor returned non-array');","typeGuard":"function isPostArray(v) {\n  return Array.isArray(v) && v.every((p) => p && typeof p === 'object');\n}","tryCatchPattern":"try {\n  const stats = await postAnalytics(posts);\n} catch (e) {\n  if (String(e.message).includes('expected an array of posts')) {\n    return postAnalytics([]); // or surface input bug\n  }\n  throw e;\n}","preventionTips":["Always default extractor results to [] instead of null/undefined","Wrap single-post inputs in an array before calling analytics","Unit-test summarize with null, object, and array inputs","Type-check pipeline outputs between fetch and analytics stages"],"tags":["linkedin","type-error","input-validation"],"backgroundTag":"unexpected-payload-shape","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}