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
- Verify the handle exists on x.com.
- Flush the cache key `twitter-userdata-{id}` to force a fresh lookup if the user was recently restored/renamed.
- 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
- Flush the twitter-userdata cache after restoring/renaming accounts
- Validate handle format before lookup
- Surface distinct errors for suspended vs unknown
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
- Tweet ID is required
- User ID is required for the v2 home timeline
- User not found
- User not found
- This creator does not exist.
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/c47ecfded23196b1.
Report an issue: GitHub.