DIYgod/RSSHub · error · Error

Unhandled media type: ${media.mimetype}

Error message

Unhandled media type: ${media.mimetype}

What it means

renderMedia switches on `media.mimetype` and handles only image/gif, image/jpeg, image/png, video/mp4, and audio/mp4; every other mimetype hits `default` and throws a generic Error. This is a parser-completeness gap.

Source

Thrown at lib/routes/fansly/utils.tsx:138

const parseMedia = (contentId, accountMedia) => {
    const media = accountMedia.find((media) => media.id === contentId);
    if (!media) {
        return '';
    }
    return renderMedia(media.preview ?? media.media);
};

const renderMedia = (media) => {
    switch (media.mimetype) {
        case 'image/gif':
        case 'image/jpeg':
        case 'image/png':
        case 'video/mp4':
        case 'audio/mp4':
            return renderToString(<FanslyMedia poster={media.mimetype === 'video/mp4' ? media.variants[0].locations[0] : null} src={media.locations[0]} />);
        default:
            throw new Error(`Unhandled media type: ${media.mimetype}`);
    }
};

const renderPoll = (pollId, polls) => {
    const poll = polls.find((poll) => poll.id === pollId);
    return renderToString(<FanslyPoll title={poll.question} options={poll.options} version={poll.version} />);
};
const renderTipGoal = (tipGoalId, tipGoals) => {
    const goal = tipGoals.find((goal) => goal.id === tipGoalId);
    return renderToString(<FanslyTipGoal label={goal.label} currentPercentage={goal.currentPercentage} currentAmount={goal.currentAmount} goalAmount={goal.goalAmount} />);
};

export { baseUrl, findAccountById, getAccountByUsername, getTagId, getTagSuggestion, getTimelineByAccountId, icon, parseAttachments, parseDescription, parseMedia, renderMedia, renderPoll, renderTipGoal };

const FanslyMedia = ({ poster, src }: { poster?: { location?: string } | null; src?: { location?: string } }) => (
    <>
        {poster && src ? (
            <video controls preload="metadata" poster={poster.location}>

View on GitHub (pinned to bed535e087)

Solutions

  1. Add the new mimetype to the switch (rendering it through FanslyMedia if the format is browser-compatible).
  2. As a stopgap, return an empty string in the `default` arm.
  3. If the format is not browser-playable, fall back to a poster/placeholder instead of throwing.

Example fix

// before
//   case 'audio/mp4':
//       return renderToString(<FanslyMedia ... />);
//   default:
//       throw new Error(`Unhandled media type: ${media.mimetype}`);
// after
//   case 'audio/mp4':
//   case 'image/webp':
//   case 'video/webm':
//       return renderToString(<FanslyMedia ... />);
//   default:
//       return '';
Defensive patterns

Strategy: fallback

Validate before calling

const HANDLED_MIME = new Set(['image/gif', 'image/jpeg', 'image/png', 'video/mp4', 'audio/mp4']);
function isHandledMime(media: { mimetype: string }): boolean {
  return HANDLED_MIME.has(media.mimetype);
}

Type guard

function isHandledMime(media: { mimetype: string }): boolean {
  return HANDLED_MIME.has(media.mimetype);
}

Try / catch

try {
  return renderMedia(media);
} catch {
  return '';
}

Prevention

When it happens

Trigger: Fansly serves a media file in a format not in the list — e.g. image/webp, image/heic, video/webm, video/quicktime.

Common situations: Fansly rolls out a new upload format; the error appears only on posts containing the new format.

Related errors


AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12). Data as JSON: /api/errors/55498ebc172c98ca. Report an issue: GitHub.