{"record":{"id":"3725551c4528b4d4","repo":"jackwener/OpenCLI","slug":"xiaohongshu-follow-user-id-must-be-a-xiaohongshu","errorCode":null,"errorMessage":"xiaohongshu/follow: user-id must be a Xiaohongshu user ID (e.g. 5d8f88dc0000000001005d3a) or full profile URL","messagePattern":"xiaohongshu/follow: user-id must be a Xiaohongshu user ID \\(e\\.g\\. 5d8f88dc0000000001005d3a\\) or full profile URL","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/follow.js","lineNumber":60,"sourceCode":"    if (/^https?:\\/\\//i.test(input)) {\n        let parsed;\n        try {\n            parsed = new URL(input);\n        } catch {\n            throw new ArgumentError('xiaohongshu/follow: invalid profile URL');\n        }\n        if (parsed.protocol !== 'https:' || !isXiaohongshuHost(parsed.hostname)) {\n            throw new ArgumentError('xiaohongshu/follow: profile URL must be an exact https://*.xiaohongshu.com URL');\n        }\n        const match = parsed.pathname.match(/^\\/user\\/profile\\/([a-zA-Z0-9]{8,32})\\/?$/);\n        if (!match) {\n            throw new ArgumentError('xiaohongshu/follow: profile URL must be /user/profile/<userId>');\n        }\n        return match[1];\n    }\n    const userId = normalizeXhsUserId(raw);\n    if (!userId || !USER_ID_RE.test(userId)) {\n        throw new ArgumentError(\n            'xiaohongshu/follow: user-id must be a Xiaohongshu user ID (e.g. 5d8f88dc0000000001005d3a) or full profile URL',\n        );\n    }\n    return userId;\n}\n\n/**\n * The injected page script. Lives in the browser context, so it can't import\n * anything — every helper is inlined. Returns `{ ok, state, reason? }` where\n * `state` is one of: 'followed' | 'already-following' | 'failed'.\n */\nfunction buildFollowScript() {\n    return `\n(async () => {\n  const FOLLOW_LABELS = ['关注', '+ 关注', '+关注'];\n  const FOLLOWING_LABELS = ['已关注', '已互关', '互相关注'];\n  const STATE_FLIP_TIMEOUT_MS = ${STATE_FLIP_TIMEOUT_MS};\n  const STATE_POLL_MS = 250;","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/follow.js#L42-L78","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nopencli xiaohongshu follow --user-id '张三的小红书'\n// after\nopencli xiaohongshu follow --user-id '5d8f88dc0000000001005d3a'","handlingStrategy":"validation","validationCode":"const USER_ID_RE = /^[a-zA-Z0-9]{8,32}$/;\nfunction isValidXhsUserId(raw) {\n  const s = String(raw ?? '').trim();\n  return USER_ID_RE.test(s) || /^https:\\/\\/([a-z0-9-]+\\.)?xiaohongshu\\.com\\/user\\/profile\\/[a-zA-Z0-9]{8,32}\\/?$/i.test(s);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await opencliFollow(userArg);\n} catch (err) {\n  if (err.code === 'ARGUMENT' && err.message.includes('user-id must be')) {\n    console.error('Expected a Xiaohongshu user ID (hex) or full profile URL');\n    process.exitCode = 2;\n  } else throw err;\n}","preventionTips":["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"],"tags":["argument-validation","cli-usage","user-id","xiaohongshu"],"backgroundTag":"invalid-argument-format","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}