DIYgod/RSSHub · warning · InvalidParameterError
User not found
Error message
User not found
What it means
Thrown by RSSHub's Twitter web-api when the GraphQL UserByRestId / UserByScreenName response contains no user.result.rest_id. RSSHub treats a missing rest_id as 'the screen name or numeric id does not resolve to an account', caches an empty placeholder so the lookup is not retried, and surfaces InvalidParameterError('User not found') so the HTTP layer returns a 400-class error to the feed reader.
Source
Thrown at lib/routes/twitter/api/web-api/api.ts:50
method: 'GET',
params,
headers: {
'accept-encoding': 'gzip',
},
});
}
return twitterGot(`${baseUrl}${id.startsWith('+') ? gqlMap.UserByRestId : gqlMap.UserByScreenName}`, params, {
allowNoAuth: !id.startsWith('+'),
});
});
const cacheTryGet = async (_id, params, operationName, func) => {
const userData: any = await getUserData(_id);
const id = userData.data?.user?.result?.rest_id;
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 getUserTweets = (id: string, params?: Record<string, any>) =>
cacheTryGet(id, params, 'getUserTweets', async (id, params = {}) =>
gatherLegacyFromData(
await paginationTweets('UserTweets', id, {
...params,
count: 20,
includePromotedContent: true,
withQuickPromoteEligibilityTweetFields: true,
withVoice: true,
withV2Timeline: true,
})
)
);
View on GitHub (pinned to bed535e087)
Solutions
- Verify the screen name resolves on x.com in a browser (open https://x.com/<id>).
- Prefix the id with '+' to force the numeric UserByRestId path, or remove the '+' to use screen-name lookup, matching the actual identifier type.
- Remove the cached empty placeholder by evicting the cache key 'twitter-userdata-<id>' (contentExpire window) so the lookup is re-attempted after the account is restored.
- If the account was renamed, update the feed URL to the new handle.
Example fix
// before // /twitter/user/someoldhandle (renamed) // after // /twitter/user/newhandle // or force numeric-id lookup // /twitter/user/+1234567890
Defensive patterns
Strategy: validation
Validate before calling
// Before subscribing, sanity-check the handle resolves.
import ofetch from 'ofetch';
async function twitterUserExists(handle: string): Promise<boolean> {
try {
const r = await ofetch(`https://x.com/i/api/graphql/xmU6X_CKVnQ5lSrCbAmJsg/UserByScreenName?variables=${encodeURIComponent(JSON.stringify({ screen_name: handle.replace(/^@/, ''), withSafetyModeUserFields: true }))}`, { headers: { authorization: 'Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D' } });
return Boolean(r?.data?.user?.result?.rest_id);
} catch { return false; }
} Type guard
function isTwitterUserResult(userData: any): userData is { data: { user: { result: { rest_id: string } } } } {
return typeof userData?.data?.user?.result?.rest_id === 'string';
} Try / catch
// RSSHub operators usually cannot edit the route; end-users should wrap feed fetches.
try {
await fetchRss('/twitter/user/<handle>');
} catch (e) {
if (/User not found/.test(String(e))) { /* remove/fix the feed */ }
else throw e;
} Prevention
- Strip leading '@' from handles before building the feed URL.
- Periodically validate stored Twitter handles against x.com since accounts get renamed/suspended.
- Use '+<numericId>' form when you have a stable numeric id to avoid screen-name churn.
When it happens
Trigger: Calling a Twitter user route (/twitter/user/:id) with a misspelled or deleted screen name, a numeric id of a suspended account, or an id whose response shape changed (Twitter occasionally drops rest_id for protected/age-gated accounts). The check fires only after userData.data.user.result.rest_id === undefined, i.e. the API answered but did not include a rest id.
Common situations: Feed URL hard-codes an old handle that the user renamed or deleted; copy-paste of a handle with a leading '@' that the route does not strip; Twitter returns a UserUnavailable payload that still has data.user but no result.rest_id; transient API outage returning a partial JSON body.
Related errors
- User not found
- This account doesn't exist
- This creator does not exist.
- Invalid Column: ${column}
- Tweet ID is required
AI-assisted analysis of DIYgod/RSSHub@bed535e087 (2026-08-12).
Data as JSON: /api/errors/c3cd2710eba46810.
Report an issue: GitHub.