{"record":{"id":"3618b153b0660420","repo":"langgenius/dify","slug":"usagemissingarg-3618b1","errorCode":"UsageMissingArg","errorMessage":"nothing to select","messagePattern":"nothing to select","errorType":"error_code","errorClass":"BaseError","httpStatus":null,"severity":"error","filePath":"cli/src/sys/io/select.ts","lineNumber":25,"sourceCode":"\nexport type SelectOptions<T> = {\n  readonly io: IOStreams\n  readonly items: readonly T[]\n  readonly header: string\n  /** Single rich line shown per option. */\n  readonly render: (item: T) => string\n  /** Optional second line shown only for the focused option in the TTY picker. */\n  readonly describe?: (item: T) => string\n}\n\nconst HIDE_CURSOR = '\\x1B[?25l'\nconst SHOW_CURSOR = '\\x1B[?25h'\nconst CLEAR_DOWN = '\\x1B[0J'\nconst cursorUp = (n: number): string => `\\x1B[${n}A`\n\nexport async function selectFromList<T>(opts: SelectOptions<T>): Promise<T> {\n  if (opts.items.length === 0)\n    throw new BaseError({ code: ErrorCode.UsageMissingArg, message: 'nothing to select' })\n  return opts.io.isErrTTY ? pickInteractive(opts) : pickNumbered(opts)\n}\n\n/**\n * Arrow-key picker built on Node's readline keypress events — no third-party\n * prompt library, so it bundles cleanly into the compiled binary. Renders to\n * the err stream, redrawing in place on each keystroke and erasing itself on\n * exit so the caller's own output starts on a clean row.\n */\nasync function pickInteractive<T>(opts: SelectOptions<T>): Promise<T> {\n  const input = opts.io.in as NodeJS.ReadStream\n  const out = opts.io.err\n  const cs = colorScheme(colorEnabled(opts.io.isErrTTY))\n  const count = opts.items.length\n\n  return new Promise<T>((resolve, reject) => {\n    let active = 0\n    let rendered = 0","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/cli/src/sys/io/select.ts#L7-L43","documentation":"BaseError(UsageMissingArg, exit 2) thrown at the top of selectFromList (select.ts:25) when opts.items is empty. This is the picker's own defensive guard, independent of any specific caller. Most callers (e.g. pickWorkspaceId in use.ts) pre-check and throw their own contextual error, so this fires for callers that pass items without pre-validation — typically a programming error in a command, not a user mistake.","triggerScenarios":"A command calls selectFromList with a list that resolved to zero entries without first checking length. E.g. listing devices, workspaces, or apps and immediately opening a picker on the result. If the upstream list call returned [], the picker rejects it here rather than rendering an empty menu.","commonSituations":"Command author forgot the empty-state guard; an API returned an unexpected empty payload; a filter removed all items; testing a new picker-based command with empty fixtures.","solutions":["If you're a user: this usually means the underlying list is empty — run the corresponding `list` subcommand to verify, then create/invite/import to populate it.","If you're calling selectFromList in code: check `items.length` first and throw a domain-specific BaseError with context (as pickWorkspaceId does for workspaces).","Provide an explicit argument (e.g. an id) to skip the picker entirely.","File a bug if a built-in command surfaces this raw message — it should be caught upstream with a friendlier error."],"exampleFix":"// before — caller passes items straight to the picker\nconst picked = await selectFromList({ io, items: devices, header: 'Select', render })\n\n// after — guard explicitly, mirror pickWorkspaceId's pattern\nif (devices.length === 0) {\n  throw new BaseError({ code: ErrorCode.AccessDenied, message: 'no devices available' })\n}\nconst picked = await selectFromList({ io, items: devices, header: 'Select', render })","handlingStrategy":"validation","validationCode":"// guard before calling selectFromList\nfunction assertNonEmpty<T>(items: readonly T[], what: string): void {\n  if (items.length === 0) {\n    throw new Error(`no ${what} available to select`)\n  }\n}\n// usage: assertNonEmpty(devices, 'devices')","typeGuard":"function hasItems<T>(items: readonly T[]): items is readonly [T, ...T[]] {\n  return items.length > 0\n}","tryCatchPattern":null,"preventionTips":["Always pre-check list length before opening a picker; throw a domain-specific error.","When the list comes from an API, handle the empty case as a first-class UX, not as a picker failure."],"tags":["cli","select","picker","empty-state","usage"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}