jackwener/OpenCLI · error · ArgumentError
xiaohongshu/follow: profile URL must be /user/profile/<userI
Error message
xiaohongshu/follow: profile URL must be /user/profile/<userId>
What it means
After validating scheme and host, assertUserId extracts the user ID from the path with /\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/. If the path doesn't match, ArgumentError is thrown. The URL is valid xiaohongshu.com but not a user profile page.
Source
Thrown at clis/xiaohongshu/follow.js:54
}
return inner;
}
function assertUserId(raw) {
const input = String(raw ?? '').trim();
if (/^https?:\/\//i.test(input)) {
let parsed;
try {
parsed = new URL(input);
} catch {
throw new ArgumentError('xiaohongshu/follow: invalid profile URL');
}
if (parsed.protocol !== 'https:' || !isXiaohongshuHost(parsed.hostname)) {
throw new ArgumentError('xiaohongshu/follow: profile URL must be an exact https://*.xiaohongshu.com URL');
}
const match = parsed.pathname.match(/^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/);
if (!match) {
throw new ArgumentError('xiaohongshu/follow: profile URL must be /user/profile/<userId>');
}
return match[1];
}
const userId = normalizeXhsUserId(raw);
if (!userId || !USER_ID_RE.test(userId)) {
throw new ArgumentError(
'xiaohongshu/follow: user-id must be a Xiaohongshu user ID (e.g. 5d8f88dc0000000001005d3a) or full profile URL',
);
}
return userId;
}
/**
* The injected page script. Lives in the browser context, so it can't import
* anything — every helper is inlined. Returns `{ ok, state, reason? }` where
* `state` is one of: 'followed' | 'already-following' | 'failed'.
*/
function buildFollowScript() {View on GitHub (pinned to 49907e53dc)
Solutions
- Use the exact /user/profile/<userId> path: https://www.xiaohongshu.com/user/profile/5d8f88dc0000000001005d3a.
- Copy the ID directly from the profile page URL while viewing the user, stripping extra path segments.
- Pass the bare user ID instead of a URL to bypass path parsing entirely.
Example fix
// before opencli xiaohongshu follow --user-id 'https://www.xiaohongshu.com/user/profile/5d8f88dc0000000001005d3a/tabs' // after opencli xiaohongshu follow --user-id '5d8f88dc0000000001005d3a'
Defensive patterns
Strategy: validation
Validate before calling
const USER_PROFILE_PATH = /^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/;
function extractXhsUserId(raw) {
const u = new URL(String(raw));
const m = u.pathname.match(USER_PROFILE_PATH);
return m ? m[1] : null;
} Try / catch
try {
await opencliFollow(url);
} catch (err) {
if (err.code === 'ARGUMENT' && err.message.includes('/user/profile/<userId>')) {
// wrong path shape — extract id or pass bare id
}
throw err;
} Prevention
- Use only /user/profile/<id> URLs, not note or tab URLs
- Strip extra path segments and query strings
- Pass the bare user ID to bypass URL path parsing
When it happens
Trigger: Passing https://www.xiaohongshu.com/explore/<noteId> or /user/<something> (wrong path shape), a profile URL with extra segments like /user/profile/<id>/tabs, a userId shorter than 8 or longer than 32 chars, or a userId containing '-' or '_' (non-alphanumeric).
Common situations: Confusing note URLs with profile URLs; using mobile app share URLs with query junk in the path; URLs to /user/profile/ landing without an id; trailing content after the id beyond an optional slash.
Related errors
- xiaohongshu/follow: invalid profile URL
- xiaohongshu/follow: user-id must be a Xiaohongshu user ID (e
- <train-no> must not be empty
- 1688 item expects an offer URL or offer ID
- Invalid 1688 store URL
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/73324d648151a07b.
Report an issue: GitHub.