koala73/worldmonitor · error
Generic adapter requires acquisition config (retailer: ${ctx
Error message
Generic adapter requires acquisition config (retailer: ${ctx.config.slug}) What it means
GenericPlaywrightAdapter.fetchTarget() delegates URL acquisition to fetchWithFallback(), which needs the retailer config's acquisition block (provider, options, optional fallback). The error fires deterministically when a retailer using the generic adapter has no acquisition field — the adapter has no other way to know which provider chain to use for its discovery seeds.
Source
Thrown at consumer-prices-core/src/adapters/generic.ts:58
return el?.getAttribute(attr.trim()) ?? null;
}
return doc.querySelector(selector)?.textContent?.trim() ?? null;
}
export class GenericPlaywrightAdapter implements RetailerAdapter {
readonly key = 'generic';
async discoverTargets(ctx: AdapterContext): Promise<Target[]> {
return ctx.config.discovery.seeds.map((s) => ({
id: s.id,
url: s.url.startsWith('http') ? s.url : `${ctx.config.baseUrl}${s.url}`,
category: s.category ?? s.id,
}));
}
async fetchTarget(ctx: AdapterContext, target: Target): Promise<FetchResult> {
if (!ctx.config.acquisition) throw new Error(`Generic adapter requires acquisition config (retailer: ${ctx.config.slug})`);
const result = await fetchWithFallback(target.url, ctx.config.acquisition, ctx.config.rateLimit ? {
timeout: 30_000,
} : undefined);
return {
url: result.url,
html: result.html,
markdown: result.markdown,
statusCode: result.statusCode,
fetchedAt: result.fetchedAt,
};
}
async parseListing(ctx: AdapterContext, result: FetchResult): Promise<ParsedProduct[]> {
const selectors = ctx.config.extraction?.productCard;
if (!selectors) return [];
const dom = new JSDOM(result.html);View on GitHub (pinned to eeab0a219f)
Solutions
- Add an acquisition block to the retailer config: { provider: 'playwright'|'firecrawl'|'p0', options?, fallback? }
- Validate retailer configs at load time (adapter-specific required fields) so this fails at startup, not per-target
- Check for schema drift — the field must be exactly 'acquisition' on the retailer config object
Example fix
// before
{ slug: 'retailer-x', baseUrl: 'https://x.example', adapter: 'generic', discovery: { seeds: [...] } }
// after
{
slug: 'retailer-x', baseUrl: 'https://x.example', adapter: 'generic',
discovery: { seeds: [...] },
acquisition: { provider: 'playwright', fallback: 'firecrawl' },
} Defensive patterns
Strategy: validation
Validate before calling
function validateGenericConfig(cfg: RetailerConfig): string[] {
const errs: string[] = [];
if (cfg.adapter === 'generic' && !cfg.acquisition) {
errs.push(`retailer '${cfg.slug}': generic adapter requires an acquisition block`);
}
return errs;
}
// at startup
const errs = retailerConfigs.flatMap(validateGenericConfig);
if (errs.length) throw new Error(errs.join('; ')); Type guard
function hasAcquisition(cfg: RetailerConfig): cfg is RetailerConfig & { acquisition: AcquisitionConfig } {
return cfg.acquisition !== undefined;
} Try / catch
try {
await adapter.fetchTarget(ctx, target);
} catch (err) {
if (err instanceof Error && err.message.includes('requires acquisition config')) {
skipRetailer(ctx.config.slug, 'misconfigured'); // permanent config bug: skip and alert, do not retry
return;
}
throw err;
} Prevention
- Run a config lint pass at deploy time that checks adapter-specific required fields
- Keep retailer config templates schema-generated so required fields cannot drift
- Treat 'requires X config' errors as permanent: skip the retailer and alert instead of retrying
When it happens
Trigger: A retailer config with adapter 'generic' and discovery.seeds but a missing or renamed acquisition section; acquisition nested at the wrong level after a config schema change; configs written for a different adapter being switched to generic without adding the field.
Common situations: Adding a new retailer from an old template that predates the acquisition field; a config schema migration renaming the block; hand-edited configs in a deploy repo drifting from the schema.
Understand the failure class
Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.
Related errors
- EXA_API_KEY is required for exa-search adapter
- Acquisition provider '${name}' is not configured. Set the re
- ExaSearchAdapter does not support single-product parsing
AI-assisted analysis of koala73/worldmonitor@eeab0a219f (2026-08-21).
Data as JSON: /api/errors/3468cc8eff9359b3.
Report an issue: GitHub.