{"record":{"id":"1163ea525d903810","repo":"TryGhost/Ghost","slug":"failed-to-create-entitytype-response-status","errorCode":null,"errorMessage":"Failed to create ${entityType}: ${response.status()} ${errorMessage}","messagePattern":"Failed to create (.+?): (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"e2e/data-factory/persistence/adapters/api.ts","lineNumber":47,"sourceCode":"        this.transformResponse = options.transformResponse || ((response: TResponse) => response as unknown);\n    }\n\n    protected buildUrl(path?: string): string {\n        const url = path ? `${this.endpoint}/${path}` : this.endpoint;\n        const params = new URLSearchParams(this.queryParams);\n        const queryString = params.toString();\n        return queryString ? `${url}?${queryString}` : url;\n    }\n\n    async insert<T>(entityType: string, data: T): Promise<T> {\n        const response = await this.httpClient.post(this.buildUrl(), {\n            data: this.transformRequest(data as unknown as TRequest)\n        });\n\n        if (!response.ok()) {\n            const errorBody = await response.json().catch(() => null);\n            const errorMessage = errorBody ? JSON.stringify(errorBody) : '';\n            throw new Error(`Failed to create ${entityType}: ${response.status()} ${errorMessage}`);\n        }\n\n        const body = await response.json() as TResponse;\n        return this.transformResponse(body) as T;\n    }\n\n    async findById<T>(entityType: string, id: string): Promise<T> {\n        const response = await this.httpClient.get(this.buildUrl(id));\n\n        if (response.status() === 404) {\n            throw new Error(`${entityType} with id ${id} not found`);\n        }\n\n        if (!response.ok()) {\n            throw new Error(`Failed to find ${entityType}: ${response.status()}`);\n        }\n\n        const body = await response.json() as TResponse;","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/TryGhost/Ghost/blob/47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe/e2e/data-factory/persistence/adapters/api.ts#L29-L65","documentation":"Thrown by ApiPersistenceAdapter.insert() when the POST to the configured endpoint returns a non-ok response. This is the test-data-factory's generic create-failure signal: it includes the HTTP status and, if the body parsed as JSON, the stringified error body. It is the e2e equivalent of a server-side create rejection — the Admin API refused to create the entity.","triggerScenarios":"A factory.create() call POSTs to e.g. /api/admin/posts/ and the server returns 4xx/5xx. Frequent causes in the e2e suite: the test's HTTP client isn't authenticated (cookies not propagated from the Playwright BrowserContext), the endpoint is wrong, a required field is missing or fails validation, or the Ghost dev server isn't running.","commonSituations":"Forgot to create the factory from an authenticated page.request (auth lives on the BrowserContext); baseURL not set so the endpoint resolves wrong; factory builds an entity violating a uniqueness constraint (e.g. duplicate slug); Ghost dev server down or still booting; field names changed after a Ghost API refactor but the factory wasn't updated.","solutions":["Read the embedded status + JSON body in the message — it names the validation failure (e.g. 422 with the field at fault).","Ensure the factory was created from an authenticated HTTP client (e.g. createPostFactory(page.request) where page is the authenticated fixture).","Confirm 'pnpm dev' is running and the admin dev server is reachable at http://127.0.0.1:5174 (per e2e AGENTS.md).","Verify the endpoint and query params passed to ApiPersistenceAdapter match the live Admin API route.","Run 'pnpm build' after factory changes and 'pnpm test:types' to catch contract drift."],"exampleFix":"// before: unauthenticated request client → 401\nconst factory = new PostFactory(new ApiPersistenceAdapter({\n    httpClient: request, // bare Playwright request, no session cookie\n    endpoint: `${baseURL}/api/admin/posts/`\n}));\nawait factory.create({title: 'X'}); // throws Failed to create posts: 401 ...\n\n// after: use the authenticated page fixture's request\nconst factory = createPostFactory(page.request); // carries the session cookie\nawait factory.create({title: 'X'});","handlingStrategy":"try-catch","validationCode":"// Verify the HTTP client is authenticated and the endpoint is reachable before bulk-creating\nasync function clientCanPost(httpClient, endpoint) {\n    const res = await httpClient.get(endpoint);\n    return res.ok() || res.status() === 404; // 404 on the collection root is often fine\n}\n\nif (await clientCanPost(httpClient, endpoint)) {\n    await factory.createMany(list);\n}","typeGuard":null,"tryCatchPattern":"try {\n    return await factory.create(options);\n} catch (err) {\n    if (/Failed to create .*: 401|403/.test(err.message)) {\n        throw new Error('Factory HTTP client is not authenticated. Create it from the authenticated page fixture.');\n    }\n    throw err;\n}","preventionTips":["Always create factories from the authenticated page.request fixture (e.g. createPostFactory(page.request)).","Ensure 'pnpm dev' is running and reachable before the suite starts.","Run 'pnpm build' and 'pnpm test:types' after factory/API contract changes."],"tags":["e2e","data-factory","api-adapter","test-infrastructure","authentication"],"backgroundTag":null,"analyzedSha":"47d8b0e2ad2fd4757d3bc45f46c3ac165ff8a1fe","analyzedAt":"2026-08-13T01:25:26.651Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}