jackwener/OpenCLI · error · ArgumentError
xiaohongshu/follow: user-id must be a Xiaohongshu user ID (e
Error message
xiaohongshu/follow: user-id must be a Xiaohongshu user ID (e.g. 5d8f88dc0000000001005d3a) or full profile URL
What it means
The catch-all branch of assertUserId: the input was neither a valid URL nor an ID matching USER_ID_RE after normalizeXhsUserId, so ArgumentError is thrown. It tells the caller the accepted formats: a Xiaohongshu user ID like 5d8f88dc0000000001005d3a, or a full profile URL.
Source
Thrown at clis/xiaohongshu/follow.js:60
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() {
return `
(async () => {
const FOLLOW_LABELS = ['关注', '+ 关注', '+关注'];
const FOLLOWING_LABELS = ['已关注', '已互关', '互相关注'];
const STATE_FLIP_TIMEOUT_MS = ${STATE_FLIP_TIMEOUT_MS};
const STATE_POLL_MS = 250;View on GitHub (pinned to 49907e53dc)
Solutions
- Open the target user's profile in a browser and copy the 24-hex-char segment from /user/profile/<id>.
- Pass that raw ID: opencli xiaohongshu follow --user-id 5d8f88dc0000000001005d3a.
- If you only have a nickname or short link, resolve it to the profile URL first, then pass the full https URL.
Example fix
// before opencli xiaohongshu follow --user-id '张三的小红书' // after opencli xiaohongshu follow --user-id '5d8f88dc0000000001005d3a'
Defensive patterns
Strategy: validation
Validate before calling
const USER_ID_RE = /^[a-zA-Z0-9]{8,32}$/;
function isValidXhsUserId(raw) {
const s = String(raw ?? '').trim();
return USER_ID_RE.test(s) || /^https:\/\/([a-z0-9-]+\.)?xiaohongshu\.com\/user\/profile\/[a-zA-Z0-9]{8,32}\/?$/i.test(s);
} Try / catch
try {
await opencliFollow(userArg);
} catch (err) {
if (err.code === 'ARGUMENT' && err.message.includes('user-id must be')) {
console.error('Expected a Xiaohongshu user ID (hex) or full profile URL');
process.exitCode = 2;
} else throw err;
} Prevention
- Remember the CLI takes the hex user ID, not the nickname
- Copy the ID from /user/profile/<id> in the address bar
- Validate the ID format (8-32 alphanumeric) before calling
- Quote arguments in shell so empty values are caught early
When it happens
Trigger: Passing a display name or nickname instead of an ID ('--user-id 小红书用户'), a numeric-only short ID, an ID with hyphens/underscores, or an empty/whitespace string to the follow command.
Common situations: Assuming the CLI accepts usernames (it requires the hex-style ID); grabbing the wrong number from a note URL (note id vs user id); shell eating quotes so the value arrives empty; using an old-format ID that no longer matches the ID regex.
Related errors
- xiaohongshu/follow: invalid profile URL
- xiaohongshu/follow: profile URL must be /user/profile/<userI
- <train-no> must not be empty
- kind
- direction
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/3725551c4528b4d4.
Report an issue: GitHub.