{"record":{"id":"cb72d96d788e3bc2","repo":"jackwener/OpenCLI","slug":"jike-notifications-api-returned-a-notification-wit","errorCode":null,"errorMessage":"Jike notifications API returned a notification without a type","messagePattern":"Jike notifications API returned a notification without a type","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/jike/notifications.js","lineNumber":53,"sourceCode":"    if (sourceType.includes('LIKE')) return '赞了你';\n    if (sourceType.includes('COMMENT')) return '评论了你';\n    if (sourceType.includes('FOLLOW')) return '关注了你';\n    if (sourceType.includes('REPOST')) return '转发了你';\n    if (sourceType.includes('MENTION')) return '提到了你';\n    if (sourceType.includes('REPLY')) return '回复了你';\n    return notification.type;\n}\n\nfunction cleanContent(value) {\n    return typeof value === 'string' ? value.replace(/\\n/g, ' ').slice(0, 100) : '';\n}\n\nfunction mapNotification(notification) {\n    if (!notification || typeof notification !== 'object' || typeof notification.id !== 'string' || !notification.id) {\n        throw new CommandExecutionError('Jike notifications API returned a malformed notification');\n    }\n    if (typeof notification.type !== 'string' || !notification.type) {\n        throw new CommandExecutionError('Jike notifications API returned a notification without a type');\n    }\n    const actionItem = notification.actionItem;\n    if (!actionItem || typeof actionItem !== 'object' || Array.isArray(actionItem)) {\n        throw new CommandExecutionError('Jike notifications API returned a malformed action item');\n    }\n    if (!Array.isArray(actionItem.users)) {\n        throw new CommandExecutionError('Jike notifications API returned a malformed users list');\n    }\n    const names = actionItem.users.map((user) => {\n        if (!user || typeof user !== 'object') {\n            throw new CommandExecutionError('Jike notifications API returned a malformed user');\n        }\n        return typeof user.screenName === 'string' ? user.screenName : '';\n    }).filter(Boolean);\n    const referenceItem = notification.referenceItem;\n    const referenceContent = referenceItem && typeof referenceItem === 'object' && !Array.isArray(referenceItem)\n        ? referenceItem.content\n        : '';","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/jike/notifications.js#L35-L71","documentation":"CommandExecutionError thrown by mapNotification when a notification object from the Jike notifications API has a valid id but its type field is missing, empty, or not a string. The type drives resolveActionLabel (mapping TYPE_LABELS and fallback heuristics), so a notification without a type cannot be labeled and the library refuses to emit a row rather than outputting an empty type.","triggerScenarios":"Calling the jike notifications command when /1.0/notifications/list returns items whose type field is absent or empty string — typically a new or deprecated notification category the CLI has not seen.","commonSituations":"Jike introduces a new notification kind served without the legacy type field; deprecated notification types removed from payloads; A/B-tested API responses omitting type; parsing the wrong endpoint version.","solutions":["Capture the raw API item to confirm which new notification shape lacks type","Retry — check whether only certain notification categories (e.g. new Jike features) trigger it and filter them out client-side","Update mapNotification/TYPE_LABELS in clis/jike/notifications.js to handle the new type or default it (e.g. `notification.type || 'UNKNOWN'`)","Pin/restore an older API behavior by requesting the notifications page via the standard web client to compare payload shapes","Report the new type upstream so TYPE_LABELS gains a mapping"],"exampleFix":"// before\nif (typeof notification.type !== 'string' || !notification.type) {\n  throw new CommandExecutionError('Jike notifications API returned a notification without a type');\n}\n// after: tolerate unknown types\nconst type = typeof notification.type === 'string' && notification.type ? notification.type : 'UNKNOWN';\n// and pass `type` through to resolveActionLabel","handlingStrategy":"type-guard","validationCode":"function hasNotificationType(n) {\n  return typeof n?.type === 'string' && n.type.length > 0;\n}\nconst usable = body.data.filter(n => hasNotificationId(n) && hasNotificationType(n));","typeGuard":"function hasNotificationType(n) {\n  return typeof n === 'object' && n !== null && typeof n.type === 'string' && n.type !== '';\n}","tryCatchPattern":"try {\n  rows = await jikeNotifications(page, limit);\n} catch (e) {\n  if (/without a type$/.test(e.message)) {\n    // new/unknown notification category: refetch and map unknown types to a label\n    rows = (await fetchRaw()).map(n => ({ ...n, type: n.type || 'UNKNOWN' })).filter(r => r.type !== 'UNKNOWN' || true);\n  } else throw e;\n}","preventionTips":["Normalize missing types to a sentinel like 'UNKNOWN' in your own mapping layer","Keep TYPE_LABELS up to date when Jike ships new notification categories","Log unknown types instead of hard-failing so the CLI degrades gracefully","Test the mapper against captured real payload samples including edge categories"],"tags":["api-contract","schema-validation","jike","notifications"],"backgroundTag":"schema-validation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}