DIYgod/RSSHub · warning · InvalidParameterError

User not found

Error message

User not found

What it means

InvalidParameterError from the Twitter developer-API cacheTryGet helper: getUserData returned no `id_str`, so the requested user/username does not resolve on Twitter. The helper also poisons the cache with an empty entry to avoid repeated lookups, then throws.

Source

Thrown at lib/routes/twitter/api/developer-api/api.ts:227

    return (response?.data ?? []).map((tweet) => mapTweetToLegacy(tweet, response.includes, cacheMap));
};

const getUserData = (id: string) =>
    cache.tryGet(`twitter-userdata-${id}`, async () => {
        const client = await getAppClient();
        const params = {
            'user.fields': 'profile_image_url,description,verified,url',
        };
        const response = id.startsWith('+') ? await client.v2.user(id.slice(1), params) : await client.v2.userByUsername(id, params);
        return mapUserToLegacy(response?.data) ?? '';
    });

const cacheTryGet = async (_id: string, params: Record<string, any> | undefined, operationName: string, func: (id: string, params?: Record<string, any>) => Promise<any>) => {
    const userData: any = await getUserData(_id);
    const id = userData?.id_str;
    if (id === undefined) {
        cache.set(`twitter-userdata-${_id}`, '', config.cache.contentExpire);
        throw new InvalidParameterError('User not found');
    }
    return cache.tryGet(getTwitterUserCacheKey(id, operationName, params), () => func(id, params), config.cache.routeExpire, false);
};

const getUserTimeline = async (id: string, params?: Record<string, any>, options: Record<string, any> = {}) => {
    const client = await getAppClient();
    const response = await client.v2.get(`users/${id}/tweets`, {
        max_results: params?.count ?? 20,
        expansions: 'author_id,attachments.media_keys,referenced_tweets.id,referenced_tweets.id.author_id',
        'tweet.fields': 'created_at,entities,conversation_id,referenced_tweets,author_id,in_reply_to_user_id',
        'user.fields': 'username,name,profile_image_url,description',
        'media.fields': 'preview_image_url,url,type,width,height,variants',
        ...options,
    });
    return mapTweetResponseToLegacy(response);
};

const getUserTweets = (id: string, params?: Record<string, any>) => cacheTryGet(id, params, 'getUserTweets', (id, params = {}) => getUserTimeline(id, params, { exclude: 'replies' }));

View on GitHub (pinned to bed535e087)

Solutions

  1. Verify the handle exists on x.com.
  2. Flush the cache key `twitter-userdata-{id}` to force a fresh lookup if the user was recently restored/renamed.
  3. Confirm the app has `tweet.read` and `users.read` scopes.
Defensive patterns

Strategy: try-catch

Validate before calling

const userData = await getUserData(_id);
if (userData?.id_str === undefined) throw new InvalidParameterError(`Twitter user not found: ${_id}`);

Type guard

const isUserData = (u: unknown): u is { id_str: string } => typeof u === 'object' && u !== null && typeof (u as any).id_str === 'string';

Try / catch

try { return await cacheTryGet(_id, params, operationName, func); }
catch (e) { if (e instanceof InvalidParameterError && /User not found/.test(e.message)) { await cache.set(`twitter-userdata-${_id}`, undefined); /* allow retry after rename */ } throw e; }

Prevention

When it happens

Trigger: Calling a developer-API function for an id/username that Twitter returns no data for — `userData.id_str` is undefined on line 224, so line 225 caches `''` and line 226 throws 'User not found'.

Common situations: Username typo, suspended/deleted account, handle renamed, or the developer API lacks the lookup scope; the cached empty entry will keep masking it until contentExpire lapses.

Related errors


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