{"record":{"id":"494bc12dedb3caf5","repo":"jackwener/OpenCLI","slug":"linkedin-company-extraction-returned-a-malformed-f","errorCode":null,"errorMessage":"LinkedIn company extraction returned a malformed followers count","messagePattern":"LinkedIn company extraction returned a malformed followers count","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"warning","filePath":"clis/linkedin/company.js","lineNumber":112,"sourceCode":"        slug = decodeURIComponent(match[1]);\n    } catch {\n        throw new CommandExecutionError('LinkedIn company extraction returned a malformed company slug');\n    }\n    return `https://${LINKEDIN_DOMAIN}/company/${encodeURIComponent(slug)}/about/`;\n}\n\nfunction normalizeCompanyInfo(info, targetUrl) {\n    if (!info || typeof info !== 'object' || Array.isArray(info)) {\n        throw new CommandExecutionError('LinkedIn company extraction returned a malformed payload');\n    }\n    if (!info.name) {\n        throw new CommandExecutionError('LinkedIn company page rendered but no company name was found (layout drift or company not found)');\n    }\n    let followers = 0;\n    if (info.followers) {\n        followers = Number(info.followers);\n        if (!Number.isFinite(followers)) {\n            throw new CommandExecutionError('LinkedIn company extraction returned a malformed followers count');\n        }\n    }\n    return {\n        name: String(info.name),\n        industry: String(info.industry || ''),\n        size: String(info.size || ''),\n        headquarters: String(info.headquarters || ''),\n        founded: String(info.founded || ''),\n        website: String(info.website || ''),\n        specialties: String(info.specialties || ''),\n        followers,\n        about: String(info.about || ''),\n        url: normalizeCompanyOutputUrl(info.url, targetUrl),\n    };\n}\n\ncli({\n    site: 'linkedin',","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/company.js#L94-L130","documentation":"normalizeCompanyInfo parses a company name/followers blob from the LinkedIn company page and coerces every field to plain strings/numbers. If the page reports a followers count but it cannot be coerced to a finite number (e.g. '1,200+ employees' markup drift or localized text), it throws to prevent propagating a NaN followers value to callers.","triggerScenarios":"Calling the LinkedIn company command when info.followers is truthy but Number(info.followers) yields NaN/Infinity — e.g. LinkedIn markup changed and the raw scraped followers string now contains 'followers', 'K'/'M' suffixes, or locale-specific separators.","commonSituations":"LinkedIn layout/attribute drift breaking the selector that captures the followers text; localized pages ('1.2M followers' in another language); the scraping regex grabbing surrounding decorative text.","solutions":["Log the raw info.followers value scraped from the page and extend/fix the extraction regex or selector to capture only digits","Pre-sanitize the string: strip commas, '+', 'followers', and expand K/M suffixes before calling Number()","Fall back to 0 followers (or omit the field) instead of throwing if the count is non-essential","Re-run the command; if persistent, check for library updates addressing LinkedIn layout drift"],"exampleFix":"// before\nfollowers = Number(info.followers);\nif (!Number.isFinite(followers)) {\n    throw new CommandExecutionError('LinkedIn company extraction returned a malformed followers count');\n}\n// after\nconst raw = String(info.followers).replace(/[,+\\s]|followers/gi, '');\nconst mult = /k$/i.test(raw) ? 1e3 : /m$/i.test(raw) ? 1e6 : 1;\nfollowers = Number.parseFloat(raw) * mult;\nif (!Number.isFinite(followers)) followers = 0;","handlingStrategy":"validation","validationCode":"function isValidFollowers(raw) { if (raw == null || raw === '') return true; const n = Number(String(raw).replace(/[,+\\s]|followers/gi, '')); return Number.isFinite(n); }\n// call before invoking: if (!isValidFollowers(rawFollowersText)) { /* sanitize or skip */ }","typeGuard":"function isFiniteCount(v) { return typeof v === 'number' ? Number.isFinite(v) : v == null || v === '' ? true : Number.isFinite(Number(String(v).replace(/[^0-9.km]/gi, ''))); }","tryCatchPattern":"try { const company = await getCompany(url); } catch (e) { if (String(e.message).includes('malformed followers count')) { company.followers = 0; } else { throw e; } }","preventionTips":["Sanitize scraped follower text (strip commas, '+', 'followers', expand K/M) before it reaches the library","Pin and update the library when LinkedIn changes markup","Treat followers as optional data and default to 0 in your consumers","Log raw scraped values in staging to catch extraction drift early"],"tags":["scraping","parsing","linkedin"],"backgroundTag":"scraped-field-parse-failure","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}