{"record":{"id":"95d38c22b6e2ba61","repo":"moeru-ai/airi","slug":"unknown-x-command-input-supported-commands","errorCode":null,"errorMessage":"Unknown X command: ${input}. Supported commands: \"post tweet: <text>\", \"search tweets: <query>\", \"like tweet: <tweetId>\", \"retweet: <tweetId>\", \"get user: <username>\", \"get timeline [count: N]\"","messagePattern":"Unknown X command: (.+?)\\. Supported commands: \"post tweet: <text>\", \"search tweets: <query>\", \"like tweet: <tweetId>\", \"retweet: <tweetId>\", \"get user: <username>\", \"get timeline \\[count: N\\]\"","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"integrations/twitter-services/src/adapters/airi-adapter.ts","lineNumber":229,"sourceCode":"      data: {\n        text: `Latest ${tweets.length} tweets from your timeline:\n${tweets.map((t: Tweet) => `- ${t.author.displayName}: ${t.text.substring(0, 80)}...`).join('\\n')}`,\n      },\n    })\n    return true\n  }\n\n  private async handleInput(input: string): Promise<void> {\n    let responseSent = false\n    try {\n      // Parse and handle X commands\n      logger.main.log('Processing X command:', input)\n\n      // Parse the command using the dedicated parsing function\n      const parsedCommand = parseTwitterCommand(input)\n\n      if (!parsedCommand) {\n        throw new Error(`Unknown X command: ${input}. Supported commands: \"post tweet: <text>\", \"search tweets: <query>\", \"like tweet: <tweetId>\", \"retweet: <tweetId>\", \"get user: <username>\", \"get timeline [count: N]\"`)\n      }\n\n      // Execute the appropriate command handler based on the parsed command\n      switch (parsedCommand.command) {\n        case 'post tweet':\n          await this.handlePostTweet(parsedCommand.content)\n          break\n\n        case 'search tweets':\n          responseSent = await this.handleSearchTweets(parsedCommand.content)\n          break\n\n        case 'like tweet':\n          await this.handleLikeTweet(parsedCommand.content)\n          break\n\n        case 'retweet':\n          await this.handleRetweet(parsedCommand.content)","sourceCodeStart":211,"sourceCodeEnd":247,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/integrations/twitter-services/src/adapters/airi-adapter.ts#L211-L247","documentation":"Thrown by handleInput when parseTwitterCommand(input) returns null, meaning the raw input did not match any recognised X command prefix ('post tweet:', 'search tweets:', 'like tweet:', 'retweet:', 'get user:', 'get timeline'). This is a plain Error listing all supported commands, raised before any handler dispatch.","triggerScenarios":"User sends free text that isn't a command, e.g. 'hello' or 'tweet hello' (missing the colon); uses an unsupported verb like 'delete tweet:'; casing/spacing differs from the parser's expected prefixes; the input is a partial command.","commonSituations":"User unfamiliar with the command grammar; LLM generated a paraphrase instead of the exact prefix; locale/casing differences; extra leading whitespace the parser does not normalise.","solutions":["Use one of the exact supported command prefixes, e.g. 'post tweet: hello'.","Improve parseTwitterCommand to be case-insensitive and whitespace-tolerant.","Have the adapter reply with the supported-commands list instead of throwing, so the user can self-correct."],"exampleFix":"// before\nconst parsedCommand = parseTwitterCommand(input)\nif (!parsedCommand) {\n  throw new Error(`Unknown X command: ${input}. Supported commands: ...`)\n}\n\n// after — surface usage instead of throwing\nconst parsedCommand = parseTwitterCommand(input)\nif (!parsedCommand) {\n  this.client.send({ type: 'input:text', data: { text: 'Unknown command. Try: post tweet: <text>, search tweets: <query>, like tweet: <id>, retweet: <id>, get user: <name>, get timeline' } })\n  return\n}","handlingStrategy":"type-guard","validationCode":"const parsedCommand = parseTwitterCommand(input)\nif (!parsedCommand) {\n  // surface the supported-commands list instead of throwing\n  this.client.send({ type: 'input:text', data: { text: 'Supported X commands: post tweet:, search tweets:, like tweet:, retweet:, get user:, get timeline' } })\n  return\n}","typeGuard":"function isUnknownCommandError(e: unknown): boolean {\n  return e instanceof Error && /Unknown X command:/.test(e.message)\n}","tryCatchPattern":"try {\n  await this.handleInput(input)\n} catch (e) {\n  if (e instanceof Error && /Unknown X command:/.test(e.message)) {\n    // already lists supported commands; optionally reprompt the user\n  } else throw e\n}","preventionTips":["Make parseTwitterCommand case-insensitive and whitespace-tolerant.","Reply with the supported-command list instead of throwing on unrecognised input.","Document the exact command grammar for end users and LLM prompt authors."],"tags":["twitter","parsing","command","adapter","user-input"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}