jackwener/OpenCLI · error · CommandExecutionError

Jike notifications API returned a malformed notification

Error message

Jike notifications API returned a malformed notification

What it means

CommandExecutionError thrown by mapNotification in clis/jike/notifications.js when a notification object from the Jike notifications API lacks a valid id. mapNotification requires each item to be a non-null object with a non-empty string id before it can be mapped into an output row; anything else is treated as a malformed API response rather than being silently skipped.

Source

Thrown at clis/jike/notifications.js:50

    if (typeof TYPE_LABELS[notification.type] === 'string') return TYPE_LABELS[notification.type];
    if (typeof actionItem.behavior === 'string' && actionItem.behavior.trim()) return actionItem.behavior.trim();
    const sourceType = String(actionItem.type || notification.actionType || notification.type || '').toUpperCase();
    if (sourceType.includes('LIKE')) return '赞了你';
    if (sourceType.includes('COMMENT')) return '评论了你';
    if (sourceType.includes('FOLLOW')) return '关注了你';
    if (sourceType.includes('REPOST')) return '转发了你';
    if (sourceType.includes('MENTION')) return '提到了你';
    if (sourceType.includes('REPLY')) return '回复了你';
    return notification.type;
}

function cleanContent(value) {
    return typeof value === 'string' ? value.replace(/\n/g, ' ').slice(0, 100) : '';
}

function mapNotification(notification) {
    if (!notification || typeof notification !== 'object' || typeof notification.id !== 'string' || !notification.id) {
        throw new CommandExecutionError('Jike notifications API returned a malformed notification');
    }
    if (typeof notification.type !== 'string' || !notification.type) {
        throw new CommandExecutionError('Jike notifications API returned a notification without a type');
    }
    const actionItem = notification.actionItem;
    if (!actionItem || typeof actionItem !== 'object' || Array.isArray(actionItem)) {
        throw new CommandExecutionError('Jike notifications API returned a malformed action item');
    }
    if (!Array.isArray(actionItem.users)) {
        throw new CommandExecutionError('Jike notifications API returned a malformed users list');
    }
    const names = actionItem.users.map((user) => {
        if (!user || typeof user !== 'object') {
            throw new CommandExecutionError('Jike notifications API returned a malformed user');
        }
        return typeof user.screenName === 'string' ? user.screenName : '';
    }).filter(Boolean);
    const referenceItem = notification.referenceItem;

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the command — if transient, a fresh fetch may return well-formed items
  2. Reduce --limit or paginate differently to see whether a specific page contains the malformed item
  3. Capture the raw /1.0/notifications/list response body and inspect the offending entry's shape
  4. If Jike changed the contract, relax the check in mapNotification to skip items without id (filter) instead of throwing, or map the new shape
  5. Report/patch: replace the throw with `if (!valid) return null;` and filter nulls in listNotifications

Example fix

// before
if (!notification || typeof notification !== 'object' || typeof notification.id !== 'string' || !notification.id) {
  throw new CommandExecutionError('Jike notifications API returned a malformed notification');
}
// after: skip malformed entries instead of failing the whole command
function mapNotification(notification) {
  if (!notification || typeof notification !== 'object' || typeof notification.id !== 'string' || !notification.id) {
    return null;
  }
  ...
}
const rows = body.data.map(mapNotification).filter(Boolean);
Defensive patterns

Strategy: type-guard

Validate before calling

function isValidNotification(n) {
  return n != null && typeof n === 'object' && typeof n.id === 'string' && n.id.length > 0;
}
const usable = body.data.filter(isValidNotification); // pre-filter before mapping

Type guard

function hasNotificationId(n) {
  return typeof n === 'object' && n !== null && typeof n.id === 'string' && n.id !== '';
}

Try / catch

try {
  rows = await jikeNotifications(page, limit);
} catch (e) {
  if (/malformed notification$/.test(e.message)) {
    // refetch once; if it persists, the API contract changed — fall back to raw items
    rows = (await fetchRaw()).filter(hasNotificationId);
  } else throw e;
}

Prevention

When it happens

Trigger: Calling the jike notifications command when the /1.0/notifications/list response contains an entry that is null, not an object, or has a missing/empty/non-string id field.

Common situations: Jike API contract change introducing new item shapes (e.g. deleted-content placeholders with no id); undocumented item types in the feed; partial/edge-case notifications (recalled content) serialized differently; API returning test/error entries inside data array.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/fb5eb5f258e427c8. Report an issue: GitHub.