jackwener/OpenCLI · error · ArgumentError
xiaohongshu/unfollow: profile URL must be /user/profile/<use
Error message
xiaohongshu/unfollow: profile URL must be /user/profile/<userId>
What it means
assertUserId accepts only canonical profile URLs whose path is exactly /user/profile/<userId> with an 8-32 alphanumeric ID. This ArgumentError is thrown when the URL is a valid https xiaohongshu.com URL but the path does not match that pattern, so no user ID can be extracted.
Source
Thrown at clis/xiaohongshu/unfollow.js:50
}
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/unfollow: invalid profile URL');
}
if (parsed.protocol !== 'https:' || !isXiaohongshuHost(parsed.hostname)) {
throw new ArgumentError('xiaohongshu/unfollow: 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/unfollow: 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/unfollow: user-id must be a Xiaohongshu user ID (e.g. 5d8f88dc0000000001005d3a) or full profile URL',
);
}
return userId;
}
/**
* Click the 已关注 / 已互关 button on the profile (idempotent if not following).
* Returns `{ ok, state }` where state is 'unfollow-clicked' | 'not-following' | 'failed'.
*/
function buildClickUnfollowScript() {
return `View on GitHub (pinned to 49907e53dc)
Solutions
- Open the target user's page in a browser and copy the address while on their profile: it must look like https://www.xiaohongshu.com/user/profile/<userId>
- Extract the ID from the URL yourself and pass just the ID: xiaohongshu unfollow 5d8f88dc0000000001005d3a
- Remove extra path segments or trailing junk after the 8-32 char alphanumeric ID (a single trailing slash is allowed)
- Confirm you have a profile URL, not a note (/explore/), board (/board/), or search (/search_result/) URL
Example fix
// before $ xiaohongshu unfollow 'https://www.xiaohongshu.com/explore/65f0a1b2000000001203e4c5' // after $ xiaohongshu unfollow 'https://www.xiaohongshu.com/user/profile/5d8f88dc0000000001005d3a'
Defensive patterns
Strategy: validation
Validate before calling
const m = new URL(input).pathname.match(/^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/);
if (!m) throw new Error('Not a profile URL: ' + input); Type guard
function isProfileUrl(input) {
try { return /^\/user\/profile\/([a-zA-Z0-9]{8,32})\/?$/.test(new URL(String(input).trim()).pathname); }
catch { return false; }
} Try / catch
try { await cli.unfollow({ 'user-id': url }); } catch (e) { if (String(e.message).includes('/user/profile/<userId>')) { /* extract ID or get the correct profile URL */ } else throw e; } Prevention
- Only copy the URL while actually on the user's profile page
- Confirm the path starts with /user/profile/
- Strip query/extra path segments — keep only /user/profile/<id>
- Store user IDs, not arbitrary page URLs, in your data
When it happens
Trigger: Passing 'https://www.xiaohongshu.com/user/profile/' (missing ID); 'https://www.xiaohongshu.com/explore/<noteId>' (a note URL, not a user profile); 'https://www.xiaohongshu.com/user/profile/<id>/follow' (extra path segments); an ID with non-alphanumeric characters or shorter/longer than 32 chars; a user page with a custom path like /user/profile/<id>?tab=... is fine, but /users/ or /profile/ variants fail.
Common situations: Grabbing the URL of a note/board/search page instead of the user's profile; copying a URL while the site was still redirecting (e.g. /discovery/item); URL-encoding the path; using a truncated URL from a log line.
Related errors
- --url must be a Discord channel URL like https://discord.com
- --url must be a Discord thread/post URL like https://discord
- id not a valid Grok URL (got "${input}")
- Invalid Instagram URL: ${raw}
- job-id must be a Midjourney UUID or https://www.midjourney.c
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/34e88de7e72f8b67.
Report an issue: GitHub.