{"record":{"id":"e3cd613824ec0d28","repo":"jackwener/OpenCLI","slug":"linkedin-post-analytics","errorCode":null,"errorMessage":"linkedin post-analytics","messagePattern":"linkedin post-analytics","errorType":"error_code","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/linkedin/post-analytics.js","lineNumber":18,"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,\n    latest_url: latest.url || '',\n  };\n}","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/post-analytics.js#L1-L36","documentation":"This EmptyResultError is thrown by summarize() when the posts argument is a valid array but contains zero posts. It tells the user the analytics ran but there was nothing to aggregate.","triggerScenarios":"Calling post-analytics on a profile/page whose fetched posts array is empty — no posts exist, or the extraction matched no post elements on the rendered page.","commonSituations":"Analyzing a brand-new or inactive profile with no posts; posts hidden by privacy settings or feed layout changes; wrong profile URL passed so the scraper landed on a page without a posts list.","solutions":["Verify the target profile/page actually has visible posts","Check the profile URL is correct and publicly accessible to the signed-in session","Retry while signed in / after scrolling so lazy-loaded posts render","Update the library if LinkedIn changed the posts feed markup causing extraction to miss posts"],"exampleFix":"// before\nconst posts = await scrapePosts(profileWithNoActivity);\n// after\nif (!posts.length) console.warn('No posts found; skipping analytics');\nelse summarize(posts);","handlingStrategy":"try-catch","validationCode":"const posts = await collectPosts();\nif (Array.isArray(posts) && posts.length === 0) {\n  console.warn('No posts available for analytics; skipping');\n}","typeGuard":"function hasPosts(v) {\n  return Array.isArray(v) && v.length > 0;\n}","tryCatchPattern":"try {\n  const stats = await postAnalytics(posts);\n} catch (e) {\n  if (e instanceof EmptyResultError || e.name === 'EmptyResultError') {\n    return { posts_analyzed: 0, total_reactions: 0, total_comments: 0 };\n  }\n  throw e;\n}","preventionTips":["Check target profiles have visible posts before analysis","Treat EmptyResultError as an expected empty-analytics outcome","Scroll/wait for lazy-loaded posts before extraction","Validate the profile URL resolves to the intended page"],"tags":["linkedin","empty-results","analytics"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}