DIYgod/RSSHub · error · TypeError

Invalid segment: ${part}

Error message

Invalid segment: ${part}

What it means

parseDuration splits a time string on ':' after stripping every character that is not a digit or colon, then Number()-converts each segment. If any segment cannot be parsed as a number the function throws a TypeError naming the offending segment. In practice the sanitisation regex makes non-numeric segments very hard to produce, so this is a defensive guard against unexpected input shapes.

Source

Thrown at lib/utils/helpers.ts:60

    return searchParamsString ?? new URLSearchParams(searchParams).toString();
}

/**
 * parse duration string to seconds
 * @param {string} timeStr - duration string like "01:01:01" / "01:01" / "59"
 * @returns {number}       - total seconds
 */
export function parseDuration(timeStr: string | undefined | null): number | undefined {
    if (!timeStr) {
        return;
    }
    const clean = timeStr.trim().replaceAll(/[^\d:]/g, '');
    const parts = clean.split(':');
    let total = 0;
    for (const [idx, part] of parts.entries()) {
        const n = Number(part);
        if (Number.isNaN(n)) {
            throw new TypeError(`Invalid segment: ${part}`);
        }
        total += n * Math.pow(60, parts.length - 1 - idx);
    }
    return total;
}

View on GitHub (pinned to bed535e087)

Solutions

  1. Normalise the input before calling parseDuration: convert full-width digits to ASCII and unicode colons to ':' (e.g. value.normalize('NFKC')).
  2. Wrap the call in try/catch and treat the duration as unknown on failure rather than crashing the route.
  3. Validate with a regex like /^(\d{1,2}:){0,2}\d{1,2}$/ before calling parseDuration.

Example fix

// before
const seconds = parseDuration(raw);
// after
const seconds = /^[0-9]+(:[0-9]+){0,2}$/.test(raw.trim()) ? parseDuration(raw) : undefined;
Defensive patterns

Strategy: validation

Validate before calling

function isValidDuration(s: string | null | undefined): boolean {
  return typeof s === 'string' && /^\d{1,2}(:\d{1,2}){0,2}$/.test(s.trim());
}
// before calling parseDuration
if (!isValidDuration(raw)) return undefined;

Type guard

const isParsableDuration = (s: unknown): s is string =>
  typeof s === 'string' && /^\d{1,2}(:\d{1,2}){0,2}$/.test(s.trim());

Try / catch

try {
  return parseDuration(raw);
} catch (e) {
  if (e instanceof TypeError && /Invalid segment/.test(e.message)) return undefined;
  throw e;
}

Prevention

When it happens

Trigger: Calling parseDuration with a string that, after replaceAll(/[^\d:]/g,''), still yields a segment Number() rejects as NaN (e.g. unusual unicode digit separators that survive the regex, or a programmatically-constructed input bypassing the documented formats 'SS', 'MM:SS', 'HH:MM:SS').

Common situations: A feed passing a localized duration format (e.g. full-width digits, non-ASCII colon variants) that the strip regex keeps; unit tests feeding adversarial strings; an upstream format change in a media route that hands parseDuration a malformed value.

Related errors


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