TryGhost/Ghost · error · Error
Cannot create without a persistence adapter. Use buildMany()
Error message
Cannot create without a persistence adapter. Use buildMany() for in-memory objects.
What it means
Thrown by Factory.createMany() when the factory was constructed without a PersistenceAdapter. Factories support two modes: build()/buildMany() produce in-memory objects (no adapter needed), while create()/createMany() persist through an adapter. Calling createMany() without an adapter is a programming error — the factory cannot know where to insert. The error message points you to the correct in-memory alternative.
Source
Thrown at e2e/data-factory/factory.ts:28
}
abstract build(options?: Partial<TOptions>): TResult;
buildMany(optionsList: Partial<TOptions>[]): TResult[] {
return optionsList.map(options => this.build(options));
}
async create(options?: Partial<TOptions>): Promise<TResult> {
if (!this.adapter) {
throw new Error('Cannot create without a persistence adapter. Use build() for in-memory objects.');
}
const data = this.build(options);
return await this.adapter.insert(this.entityType, data) as Promise<TResult>;
}
async createMany(optionsList: Partial<TOptions>[]): Promise<TResult[]> {
if (!this.adapter) {
throw new Error('Cannot create without a persistence adapter. Use buildMany() for in-memory objects.');
}
const results: TResult[] = [];
for (const options of optionsList) {
const result = await this.create(options);
results.push(result);
}
return results;
}
}
View on GitHub (pinned to 47d8b0e2ad)
Solutions
- If you want persisted entities, pass an adapter when constructing the factory (e.g. new ApiPersistenceAdapter({httpClient: page.request, endpoint: '/api/admin/posts/'})).
- If you only need in-memory objects, call buildMany(optionsList) instead of createMany(optionsList).
- If the adapter is conditionally available, guard the createMany call behind an 'if (factory has adapter)' check.
- Run 'pnpm build' after factory changes (per the e2e AGENTS.md) to catch wiring issues.
Example fix
// before: no adapter, persistence impossible
const factory = new PostFactory();
const posts = await factory.createMany([{status: 'published'}, {status: 'draft'}]);
// after: wire an adapter for persistence
const adapter = new ApiPersistenceAdapter({httpClient: page.request, endpoint: `${baseURL}/api/admin/posts/`});
const factory = new PostFactory(adapter);
const posts = await factory.createMany([{status: 'published'}, {status: 'draft'}]);
// or, for in-memory only, use buildMany:
const factory = new PostFactory();
const posts = factory.buildMany([{status: 'published'}, {status: 'draft'}]); Defensive patterns
Strategy: validation
Validate before calling
import {Factory} from './factory';
function assertAdapter(factory) {
if (!factory.adapter) {
throw new Error(`${factory.constructor.name} has no persistence adapter. Pass one to the constructor, or use buildMany() for in-memory objects.`);
}
}
// Before calling createMany:
assertAdapter(factory);
await factory.createMany(list); Type guard
function hasAdapter(factory) {
return factory instanceof Factory && factory.adapter != null;
} Prevention
- Construct factories with an adapter when you need persistence; use a factory helper like createPostFactory(page.request) that wires the adapter for you.
- Use build()/buildMany() deliberately when you only need in-memory data.
- Run 'pnpm build' after factory changes to catch wiring regressions.
When it happens
Trigger: Test code instantiates a factory via 'new MyFactory()' (no adapter) and then calls factory.createMany([...]) expecting persistence. The base Factory class guards both create() and createMany() with this check; createMany() specifically tells you to use buildMany().
Common situations: Copied a factory usage pattern but forgot to wire the adapter (ApiPersistenceAdapter or KnexPersistenceAdapter); refactored a test from persisted to in-memory data but left a createMany() call; factory was constructed with a null/undefined adapter argument.
Related errors
- Failed to create ${entityType}: ${response.status()} ${error
- ${entityType} with id ${id} not found
- Failed to update ${entityType}: ${response.status()}
- Cannot insert without an id field
- Failed to find ${entityType}: ${response.status()}
AI-assisted analysis of TryGhost/Ghost@47d8b0e2ad (2026-08-13).
Data as JSON: /api/errors/24e2feba61b96879.
Report an issue: GitHub.