musistudio/claude-code-router · error · Error
ToolHub resolver requires TOOLHUB_OPENAI_API_KEY and TOOLHUB
Error message
ToolHub resolver requires TOOLHUB_OPENAI_API_KEY and TOOLHUB_OPENAI_MODEL.
What it means
Thrown when the ToolHub resolver (which uses an OpenAI-compatible chat model to map a natural-language query to catalog tools) has neither an API key nor a model configured. It checks config values first, then the TOOLHUB_OPENAI_API_KEY and TOOLHUB_OPENAI_MODEL environment variables, and throws if either is missing.
Source
Thrown at packages/core/src/mcp/toolhub-mcp.ts:1482
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 ?? "",
query
}, null, 2)
}
];
let didCallAnalyzer = false;View on GitHub (pinned to 99f24806c6)
Solutions
- Set TOOLHUB_OPENAI_API_KEY and TOOLHUB_OPENAI_MODEL in the environment where the process runs
- Or pass openAiApiKey and openAiModel explicitly in the ToolHub config object
- For local/CCR gateways, also set TOOLHUB_OPENAI_BASE_URL and ensure the gateway is up
Example fix
// before
const toolhub = new ToolHubClient({});
// after
const toolhub = new ToolHubClient({ openAiApiKey: process.env.TOOLHUB_OPENAI_API_KEY!, openAiModel: process.env.TOOLHUB_OPENAI_MODEL! }); Defensive patterns
Strategy: validation
Validate before calling
const required = ["TOOLHUB_OPENAI_API_KEY", "TOOLHUB_OPENAI_MODEL"];
const missing = required.filter(k => !process.env[k]);
if (missing.length) throw new Error(`Missing env: ${missing.join(", ")}`); Try / catch
try {
await toolhub.resolve({ query });
} catch (e) {
if (e instanceof Error && e.message.includes("TOOLHUB_OPENAI")) {
// configuration problem: fail fast with clear ops message
failDeployment(e.message);
}
throw e;
} Prevention
- Add a startup assertion for ToolHub env vars
- Keep .env.example in sync with required ToolHub variables
- Fail fast in CI when resolve is exercised without config
When it happens
Trigger: Invoking resolve() without setting openAiApiKey/openAiModel in config and without both TOOLHUB_OPENAI_API_KEY and TOOLHUB_OPENAI_MODEL in the environment.
Common situations: Missing .env entries in local dev; CI/containers where ToolHub env vars aren't exported; only one of the two vars set (key but no model name); custom baseURL (e.g. local gateway) set but key/model forgotten.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- OpenAI resolve retrieval returned no assistant message.
- OpenAI resolve retrieval returned no assistant content or to
- No Bot Gateway conversationRef is available for media respon
- OpenCode App was not found. Install OpenCode App or set OPEN
- ToolHub resolve query must be non-empty.
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/3848107ad0f82134.
Report an issue: GitHub.