musistudio/claude-code-router · warning · Error

ToolHub resolve query must be non-empty.

Error message

ToolHub resolve query must be non-empty.

What it means

Thrown by the ToolHub resolve flow when the natural-language query, after trimming, is empty. The resolver cannot search a catalog without a query, so this is a fast-fail input validation before any network or LLM work occurs.

Source

Thrown at packages/core/src/mcp/toolhub-mcp.ts:1476

class OpenAiToolHubSearchAgent {
  private readonly analyzer = new ToolReferenceAnalyzer();

  constructor(private readonly config: {
    openAiApiKey?: string;
    openAiBaseUrl?: string;
    openAiModel?: string;
  }) {}

  async search(input: {
    catalog: SearchCatalogItem[];
    code?: string;
    query: string;
    timeoutMs?: number;
    topK?: number;
  }): Promise<SearchResult> {
    const query = input.query.trim();
    if (!query) {
      throw new Error("ToolHub resolve query must be non-empty.");
    }
    const apiKey = this.config.openAiApiKey || env("TOOLHUB_OPENAI_API_KEY");
    const baseURL = this.config.openAiBaseUrl || env("TOOLHUB_OPENAI_BASE_URL") || "https://api.openai.com/v1";
    const model = this.config.openAiModel || env("TOOLHUB_OPENAI_MODEL");
    if (!apiKey || !model) {
      throw new Error("ToolHub resolver requires TOOLHUB_OPENAI_API_KEY and TOOLHUB_OPENAI_MODEL.");
    }

    const topK = normalizeTopK(input.topK);
    const timeoutMs = normalizeSearchTimeout(input.timeoutMs);
    const deadlineAt = Date.now() + timeoutMs;
    await waitForLocalResolverEndpoint(baseURL, apiKey, timeoutMs);
    const client = new OpenAI({ apiKey, baseURL });
    const messages: SearchMessage[] = [
      {
        role: "user",
        content: JSON.stringify({
          context: input.code ?? "",

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Ensure the caller passes a non-empty, meaningful natural-language query
  2. Trim and check user input before calling resolve
  3. Add an upstream UI/CLI guard rejecting empty prompts

Example fix

// before
await toolhub.resolve({ query: userPrompt /* may be "" */ });

// after
const q = (userPrompt ?? "").trim();
if (!q) throw new Error("Prompt is required");
await toolhub.resolve({ query: q });
Defensive patterns

Strategy: validation

Validate before calling

const query = String(input.query ?? "").trim();
if (!query) {
  throw new Error("Query is required");
}
await toolhub.resolve({ query });

Type guard

const hasNonEmptyQuery = (q: unknown): q is string =>
  typeof q === "string" && q.trim().length > 0;

Prevention

When it happens

Trigger: Calling the ToolHub resolve API with a query of "", " ", or a value that trims to empty (undefined coerced/typed as empty string).

Common situations: Passing an unvalidated user prompt straight through; template strings that interpolate undefined; whitespace-only input from a CLI arg or form field.

Related errors


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/8c8f9540f8f4fce9. Report an issue: GitHub.