koala73/worldmonitor · error
EXA_API_KEY is required for exa-search adapter
Error message
EXA_API_KEY is required for exa-search adapter
What it means
ExaSearchAdapter.fetchTarget() guards on this.apiKey and throws before any network call. The adapter is constructible with an empty key — the constructor does not validate — so the misconfiguration survives until the first target is fetched, even though the class ships validateConfig(), which reports 'EXA_API_KEY env var is required for adapter: exa-search' for exactly this case.
Source
Thrown at consumer-prices-core/src/adapters/exa-search.ts:136
}
return targets;
}
private buildQuery(canonicalName: string, currency: string, marketCode: string, template?: string): string {
const market = MARKET_NAMES[marketCode] ?? '';
if (template) {
return template
.replace('{canonicalName}', canonicalName)
.replace('{currency}', currency)
.replace('{market}', market)
.trim();
}
return `${canonicalName} ${market} ${currency} price`.trim();
}
async fetchTarget(ctx: AdapterContext, target: Target): Promise<FetchResult> {
if (!this.apiKey) throw new Error('EXA_API_KEY is required for exa-search adapter');
const { canonicalName, domain, currency, basketSlug } = target.metadata as {
canonicalName: string;
domain: string;
currency: string;
basketSlug: string;
};
const searchQuery = this.buildQuery(
canonicalName,
currency,
ctx.config.marketCode,
ctx.config.acquisition?.searchQueryTemplate,
);
const body = {
query: searchQuery,
numResults: 5,View on GitHub (pinned to eeab0a219f)
Solutions
- Set EXA_API_KEY in the environment the adapter process reads
- Call adapter.validateConfig(retailerConfig) during bootstrap and refuse to start when it returns errors
- Fail adapter construction on a missing key so the failure happens at wiring time, not per-target
- Log which retailer configs select the exa-search adapter so the blast radius is obvious
Example fix
// before — constructible with an empty key, fails per-target later
const adapter = new ExaSearchAdapter(process.env.EXA_API_KEY ?? '');
// after — fail at construction; keep validateConfig as the config-level check
const key = process.env.EXA_API_KEY;
if (!key) throw new Error('EXA_API_KEY is not set — cannot wire exa-search adapter');
const adapter = new ExaSearchAdapter(key); Defensive patterns
Strategy: validation
Validate before calling
const errs = await adapter.validateConfig(retailerConfig);
if (errs.length) throw new Error(`exa-search config invalid: ${errs.join('; ')}`); Type guard
function exaAdapterReady(adapter: ExaSearchAdapter): boolean {
// mirror the internal guard without triggering the per-target throw
return Boolean((adapter as unknown as { apiKey?: string }).apiKey);
} Try / catch
try {
await adapter.fetchTarget(ctx, target);
} catch (err) {
if (err instanceof Error && err.message.includes('EXA_API_KEY is required')) {
abortRun('exa-search misconfigured'); // config error: stop, do not retry — it cannot succeed
}
throw err;
} Prevention
- Run validateConfig() for every adapter at startup and abort on any returned error string
- Gate adapter wiring on env presence: skip registering exa-search when EXA_API_KEY is unset
- Distinguish config errors from network errors in the runner: config errors abort, network errors retry
When it happens
Trigger: Constructing ExaSearchAdapter('') or with process.env.EXA_API_KEY undefined, then running the adapter pipeline; executing the exa-search adapter in CI without secrets mounted; skipping the validateConfig() step during adapter bootstrap.
Common situations: A new environment (local/CI/staging) missing EXA_API_KEY while production has it; secrets mounted after process start; the exa-search adapter registered as the default for search retailers with no startup config check.
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
- Acquisition provider '${name}' is not configured. Set the re
- Generic adapter requires acquisition config (retailer: ${ctx
- Exa returned no content for ${url}
- Exa returned malformed structured summary for ${url}
- Exa ${endpoint.slice(1)} failed HTTP ${response.status}: ${d
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/50e5cb7c17744821.
Report an issue: GitHub.