DIYgod/RSSHub · error · TypeError

Invalid user ID type

Error message

Invalid user ID type

What it means

Defensive TypeError from getUserId: the cached value for `threads:userId:{user}` is truthy but neither a string nor a number. The narrowing on lines 83-88 does not match, so execution falls through to the TypeError on line 90.

Source

Thrown at lib/routes/threads/utils.ts:90

                    return data[0];
                }
            } catch {
                // Skip invalid JSON
            }
        }

        throw new NotFoundError('User ID not found');
    });

    if (result) {
        if (typeof result === 'string') {
            return result;
        }
        if (typeof result === 'number') {
            return result.toString();
        }
    }
    throw new TypeError('Invalid user ID type');
};

const hasMedia = (post) => post.image_versions2 || post.carousel_media || post.video_versions;

const buildMedia = (post) => {
    let html = '';

    if (post.carousel_media) {
        for (const media of post.carousel_media) {
            const firstImage = media.image_versions2?.candidates[0];
            const firstVideo = media.video_versions?.[0];
            html += firstVideo ? `<video controls autoplay loop poster="${firstImage.url}"><source src="${firstVideo.url}"/></video>` : `<img src="${firstImage.url}"/>`;
        }
    } else {
        const mainImage = post.image_versions2?.candidates?.[0];
        const mainVideo = post.video_versions?.[0];
        if (mainImage) {
            html += mainVideo ? `<video controls autoplay loop poster="${mainImage.url}"><source src="${mainVideo.url}"/></video>` : `<img src="${mainImage.url}"/>`;

View on GitHub (pinned to bed535e087)

Solutions

  1. Flush the cache key `threads:userId:{user}` so it recomputes with current code.
  2. Audit getUserId's return path to ensure it only ever stores a string/number primitive.
  3. Coerce defensively before the type check: if Array.isArray(result) take result[0].

Example fix

// before
if (result) {
    if (typeof result === 'string') return result;
    if (typeof result === 'number') return result.toString();
}
throw new TypeError('Invalid user ID type');
// after
const id = Array.isArray(result) ? result[0] : result;
if (typeof id === 'string') return id;
if (typeof id === 'number') return id.toString();
throw new TypeError('Invalid user ID type');
Defensive patterns

Strategy: validation

Validate before calling

const cached = await cache.get(`threads:userId:${user}`);
if (cached !== undefined && typeof cached !== 'string' && typeof cached !== 'number') {
    await cache.set(`threads:userId:${user}`, undefined); // purge bad entry
}

Type guard

const isPrimitiveId = (v: unknown): v is string | number => typeof v === 'string' || typeof v === 'number';

Try / catch

try { return await getUserId(user); }
catch (e) { if (e instanceof TypeError) { await cache.set(`threads:userId:${user}`, undefined); return getUserId(user); } throw e; }

Prevention

When it happens

Trigger: A prior cache write stored an object/array (e.g. the raw JSONPath result array instead of `data[0]`), and on a subsequent read getUserId receives that non-primitive and cannot coerce it. The cache contract was violated by a code change or manual cache entry.

Common situations: Refactor that returned the whole JSONPath array instead of the first element; Redis cache polluted by an older incompatible build; the value was manually injected for testing.

Related errors


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