{"record":{"id":"0bbaeb9a9cc9d77b","repo":"jackwener/OpenCLI","slug":"linkedin-connection-miniprofile-field-field-was","errorCode":null,"errorMessage":"LinkedIn connection miniProfile field ${field} was malformed","messagePattern":"LinkedIn connection miniProfile field (.+?) was malformed","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/linkedin/connections.js","lineNumber":46,"sourceCode":"        if (!res.ok) return { error: 'HTTP ' + res.status };\n        const contentType = res.headers?.get?.('content-type') || '';\n        if (/\\btext\\/html\\b/i.test(contentType)) {\n            return { authRequired: true, error: 'HTML auth/checkpoint response' };\n        }\n        try {\n            return { json: await res.json() };\n        } catch {\n            return { error: 'response was not valid JSON' };\n        }\n    } catch (e) {\n        return { error: 'fetch failed: ' + ((e && e.message) || String(e)) };\n    }\n}\n\nfunction optionalText(value, field) {\n    if (value == null) return '';\n    if (typeof value !== 'string') {\n        throw new CommandExecutionError(`LinkedIn connection miniProfile field ${field} was malformed`);\n    }\n    return normalizeWhitespace(value);\n}\n\nfunction mapConnection(element, index) {\n    const mini = element && element.miniProfile;\n    if (!mini || typeof mini !== 'object') {\n        throw new CommandExecutionError('LinkedIn connections returned an element without a miniProfile');\n    }\n    const publicId = optionalText(mini.publicIdentifier, 'publicIdentifier');\n    if (!publicId || /[\\s/?#]/.test(publicId)) {\n        throw new CommandExecutionError('LinkedIn connection element missing a stable public identifier');\n    }\n    const name = normalizeWhitespace([\n        optionalText(mini.firstName, 'firstName'),\n        optionalText(mini.lastName, 'lastName'),\n    ].filter(Boolean).join(' ')) || publicId;\n    return {","sourceCodeStart":28,"sourceCodeEnd":64,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/linkedin/connections.js#L28-L64","documentation":"optionalText() in connections.js validates fields of each connection's miniProfile object from LinkedIn's /voyager/api/relationships/connections response. If a field like publicIdentifier, firstName, lastName or occupation is present but not a string (e.g. a number, object, or array due to a Voyager schema change), it throws CommandExecutionError naming the offending field.","triggerScenarios":"Mapping a connection element (via mapConnection -> publicId/name/occupation) where miniProfile.<field> is non-null and non-string, e.g. LinkedIn returns publicIdentifier as a structured object or firstName as a localized text object.","commonSituations":"LinkedIn silently changing the Voyager miniProfile schema; A/B test cohorts receiving new field shapes; accounts where a contact has no public profile so publicIdentifier takes an unexpected type.","solutions":["Update the library to the latest version in case a schema-change fix was released.","Capture the raw API payload and file an issue including the malformed field name from the message.","As a workaround, downgrade the limit or retry later — LinkedIn A/B variants sometimes revert.","Patch optionalText locally to coerce known object shapes (e.g. {text}) via normalizeWhitespace(String(value.text))."],"exampleFix":"// before\nif (typeof value !== 'string') {\n    throw new CommandExecutionError(`LinkedIn connection miniProfile field ${field} was malformed`);\n}\n// after\nif (typeof value !== 'string') {\n    if (value && typeof value === 'object' && typeof value.text === 'string') return normalizeWhitespace(value.text);\n    throw new CommandExecutionError(`LinkedIn connection miniProfile field ${field} was malformed`);\n}","handlingStrategy":"type-guard","validationCode":"if (mini.publicIdentifier != null && typeof mini.publicIdentifier !== 'string') {\n  throw new Error('miniProfile.publicIdentifier is not a string — LinkedIn schema may have changed.');\n}","typeGuard":"function isTextField(v) {\n  return v == null || typeof v === 'string';\n}\nconst miniOk = isTextField(mini.publicIdentifier) && isTextField(mini.firstName) && isTextField(mini.lastName);","tryCatchPattern":"try {\n  const rows = await opencli.linkedin.connections({ limit: 20 });\n} catch (e) {\n  if (e.name === 'CommandExecutionError' && /miniProfile field .* was malformed/.test(e.message)) {\n    console.warn('LinkedIn schema drift on field:', e.message.match(/field (\\w+)/)?.[1]);\n    return [];\n  }\n  throw e;\n}","preventionTips":["Pin and regularly update the CLI; Voyager schema drift is fixed upstream.","Validate captured API payloads against expected miniProfile fields in tests.","Watch for reports of field-shape changes after LinkedIn releases."],"tags":["linkedin","schema-validation","api-change"],"backgroundTag":"unexpected-api-schema","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}