{"record":{"id":"6e5230065e54ac37","repo":"jackwener/OpenCLI","slug":"at-least-one-twitter-x-username-is-required","errorCode":null,"errorMessage":"At least one Twitter/X username is required","messagePattern":"At least one Twitter/X username is required","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"clis/twitter/follow-batch.js","lineNumber":12,"sourceCode":"import { ArgumentError, AuthRequiredError, CommandExecutionError } from '@jackwener/opencli/errors';\nimport { cli, Strategy } from '@jackwener/opencli/registry';\nimport { unwrapBrowserResult } from './shared.js';\n\nconst USERNAME_RE = /^[A-Za-z0-9_]{1,15}$/;\nconst DEFAULT_DELAY_MS = 3000;\nconst MAX_DELAY_MS = 60000;\n\nexport function parseBatchUsernames(input) {\n    const raw = String(input || '').trim();\n    if (!raw) {\n        throw new ArgumentError('At least one Twitter/X username is required');\n    }\n\n    const usernames = [];\n    const seen = new Set();\n    for (const part of raw.split(',')) {\n        const username = part.trim().replace(/^@+/, '');\n        if (!username) continue;\n        if (!USERNAME_RE.test(username)) {\n            throw new ArgumentError(`Invalid Twitter/X username: ${JSON.stringify(part.trim())}`);\n        }\n        const key = username.toLowerCase();\n        if (seen.has(key)) continue;\n        seen.add(key);\n        usernames.push(username);\n    }\n\n    if (!usernames.length) {\n        throw new ArgumentError('At least one Twitter/X username is required');","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/twitter/follow-batch.js#L1-L30","documentation":"parseBatchUsernames throws ArgumentError when its input string is empty or only whitespace (String(input || '').trim() yields ''). The follow-batch command requires at least one Twitter/X screen name to act on. This is a usage/argument validation error (ARGUMENT, usage exit code).","triggerScenarios":"Running `twitter follow-batch` without the required positional `usernames` argument; passing an empty string (usernames: '') or whitespace-only string; passing null/undefined programmatically (|| '' collapses falsy values).","commonSituations":"Shell quoting mistakes that drop the positional arg (e.g. an unexpanded empty variable $USERS); scripting the CLI and forgetting the argument; calling the exported function directly with an optional/undefined value.","solutions":["Pass at least one username: `opencli twitter follow-batch '@alice'` or comma-separated '@alice,@bob'.","If sourcing from a variable/file, check it is non-empty before invoking (e.g. [ -n \"$USERS\" ] || exit 1).","Quote the variable (\"$USERS\") so the shell passes it correctly even when it contains commas/spaces."],"exampleFix":"// before\nawait cli({ usernames: process.env.USERS }) // USERS unset -> ''\n// after\nif (!process.env.USERS) throw new Error('USERS env var required');\nawait cli({ usernames: process.env.USERS })","handlingStrategy":"validation","validationCode":"function requireUsernames(input) {\n  const raw = String(input ?? '').trim();\n  if (!raw) throw new Error('usernames: at least one Twitter/X screen name is required');\n  return raw;\n}\n// in shell: [ -n \"$USERS\" ] || { echo 'USERS required' >&2; exit 1; }","typeGuard":"function hasUsernames(v) {\n  return typeof v === 'string' && v.trim().length > 0;\n}","tryCatchPattern":"try {\n  await followBatch(usernames);\n} catch (e) {\n  if (e.code === 'ARGUMENT') {\n    console.error('Usage: twitter follow-batch <@user1,@user2> [--delay-ms N]');\n    process.exitCode = 2;\n  } else throw e;\n}","preventionTips":["Always quote positional username arguments in shell scripts.","Check env/config variables are non-empty before passing them as `usernames`.","Remember `String(input || '')` coerces null/undefined/0 to empty — supply real values.","Build follow lists programmatically and assert length >= 1 before invoking."],"tags":["argument-validation","twitter","cli-usage","empty-input"],"backgroundTag":"missing-required-argument","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}