How to Fix 'invalid API key when scaling' in LlamaIndex (TypeScript)
When you see invalid API key when scaling in a LlamaIndex TypeScript app, it usually means the request reached the model provider with the wrong credential, or no credential at all. In practice, this shows up during indexing, query-time retrieval, or when you move code from local dev into a serverless/runtime environment.
The annoying part is that the error often looks like a scaling issue, but it’s usually config drift: the key exists in one place, but not where OpenAI, AzureOpenAI, or your LlamaIndex integration is actually reading from.
The Most Common Cause
The #1 cause is creating the LLM or embedding client before your environment variables are loaded, or passing the wrong env var name. In TypeScript, this happens a lot when people instantiate Settings.llm, OpenAI, or OpenAIEmbedding at module scope and expect runtime config to be available later.
Here’s the broken pattern versus the fixed one:
| Broken | Fixed |
|---|---|
| Client created before env load | Load env first, then create client |
| Wrong variable name | Use the exact provider env var |
| Hidden fallback to empty string | Fail fast if key is missing |
// BROKEN
import "dotenv/config";
import { OpenAI } from "llamaindex";
const llm = new OpenAI({
apiKey: process.env.OPEN_AI_KEY || "", // wrong var name + empty fallback
model: "gpt-4o-mini",
});
await llm.complete("Hello");
// FIXED
import "dotenv/config";
import { OpenAI } from "llamaindex";
const apiKey = process.env.OPENAI_API_KEY;
if (!apiKey) {
throw new Error("Missing OPENAI_API_KEY");
}
const llm = new OpenAI({
apiKey,
model: "gpt-4o-mini",
});
await llm.complete("Hello");
If you’re using Settings, the same rule applies:
// BROKEN
import { Settings, OpenAI } from "llamaindex";
Settings.llm = new OpenAI({
apiKey: process.env.OPENAI_API_KEY ?? "",
});
// FIXED
import "dotenv/config";
import { Settings, OpenAI } from "llamaindex";
const apiKey = process.env.OPENAI_API_KEY;
if (!apiKey) throw new Error("OPENAI_API_KEY is required");
Settings.llm = new OpenAI({ apiKey });
The main failure mode here is that LlamaIndex will happily construct objects with an empty or undefined key until the first network call. Then you get provider-level auth errors like:
- •
401 Unauthorized - •
Invalid API key provided - •
OpenAIError: Incorrect API key provided - •In some wrapper paths:
invalid API key when scaling
Other Possible Causes
1. You set the right key locally, but not in production
This is common in Vercel, Docker, ECS, and GitHub Actions. Your .env works on your laptop, but the deployed runtime has no secret.
# local works
OPENAI_API_KEY=sk-proj-...
# docker-compose.yml
services:
app:
environment:
- OPENAI_API_KEY=${OPENAI_API_KEY}
If ${OPENAI_API_KEY} is missing in your shell or CI secret store, your container gets an empty value.
2. You’re using Azure/OpenRouter/another provider with OpenAI-style classes
LlamaIndex TypeScript has provider-specific configuration. If you use OpenAI against Azure endpoints without setting Azure fields correctly, auth fails even though the key looks valid.
// BROKEN
new OpenAI({
apiKey: process.env.AZURE_OPENAI_API_KEY!,
model: "gpt-4o-mini",
});
// FIXED for Azure-style setup
import { AzureOpenAI } from "llamaindex";
new AzureOpenAI({
apiKey: process.env.AZURE_OPENAI_API_KEY!,
endpoint: process.env.AZURE_OPENAI_ENDPOINT!,
deploymentName: process.env.AZURE_OPENAI_DEPLOYMENT!,
});
3. Your embedding model uses a different credential than your chat model
A lot of teams fix Settings.llm and forget Settings.embedModel. Indexing then fails during chunk embedding with an auth error that looks unrelated to chat.
import { Settings, OpenAI, OpenAIEmbedding } from "llamaindex";
Settings.llm = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! });
Settings.embedModel = new OpenAIEmbedding({
apiKey: process.env.EMBEDDING_API_KEY!, // may be missing or different account
});
Make sure both keys exist and belong to accounts allowed for those models.
4. You’re accidentally overwriting config in another file
This happens when one module sets valid credentials and another module resets them later.
// config.ts
Settings.llm = new OpenAI({ apiKey: process.env.OPENAI_API_KEY! });
// later in another file
Settings.llm = new OpenAI({ apiKey: "" }); // accidental overwrite
Search for every new OpenAI(, new AzureOpenAI(, and every assignment to Settings.llm / Settings.embedModel.
How to Debug It
- •Print the resolved value before constructing the client
- •Don’t print the full secret.
- •Print presence and length only.
const key = process.env.OPENAI_API_KEY;
console.log("OPENAI_API_KEY present:", Boolean(key), "length:", key?.length);
- •
Check whether the failure happens at embedding time or query time
- •If it fails while building an index, inspect
Settings.embedModel. - •If it fails on chat/query calls, inspect
Settings.llm.
- •If it fails while building an index, inspect
- •
Search for duplicate client setup
- •Look for multiple files setting:
- •
Settings.llm - •
Settings.embedModel - •
new OpenAI(...) - •
new AzureOpenAI(...)
- •
- •One bad override is enough to break everything.
- •Look for multiple files setting:
- •
Run a minimal direct provider call outside LlamaIndex
- •If raw SDK auth fails too, this is not a LlamaIndex bug.
- •If raw SDK works but LlamaIndex fails, your wrapper config is wrong.
Prevention
- •Load environment variables once at startup and fail fast if required keys are missing.
- •Keep provider setup in one file so you don’t accidentally override
Settings. - •Use explicit config objects per environment:
- •local
.env - •staging secrets manager
- •production secret store
- •local
A good production pattern is to centralize validation:
export function requireEnv(name: string): string {
const value = process.env[name];
if (!value) throw new Error(`Missing ${name}`);
return value;
}
Then wire LlamaIndex only after validation:
import { Settings, OpenAI } from "llamaindex";
import { requireEnv } from "./env";
Settings.llm = new OpenAI({
apiKey: requireEnv("OPENAI_API_KEY"),
});
If you’re still seeing invalid API key when scaling, assume misconfigured runtime first. In TypeScript projects with LlamaIndex, that message almost always means “the wrong secret reached the wrong client,” not “the model can’t scale.”
Keep learning
- •The complete AI Agents Roadmap — my full 8-step breakdown
- •Free: The AI Agent Starter Kit — PDF checklist + starter code
- •Work with me — I build AI for banks and insurance companies
By Cyprian Aarons, AI Consultant at Topiax.
Want the complete 8-step roadmap?
Grab the free AI Agent Starter Kit — architecture templates, compliance checklists, and a 7-email deep-dive course.
Get the Starter Kit