{"record":{"id":"31f05970952dc357","repo":"withastro/astro","slug":"the-renderer-you-passed-isn-t-valid-a-renderer-is","errorCode":null,"errorMessage":"The renderer you passed isn't valid. A renderer is usually an object that exposes the `check` and `renderToStaticMarkup` functions.\nUsually, the renderer is exported by a /server.js entrypoint e.g. `import renderer from '@astrojs/react/server.js'`","messagePattern":"The renderer you passed isn't valid\\. A renderer is usually an object that exposes the `check` and `renderToStaticMarkup` functions\\.\nUsually, the renderer is exported by a /server\\.js entrypoint e\\.g\\. `import renderer from '@astrojs/react/server\\.js'`","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/container/index.ts","lineNumber":402,"sourceCode":"\t * import reactRenderer from \"@astrojs/react/server.js\";\n\t * import vueRenderer from \"@astrojs/vue/server.js\";\n\t * import customRenderer from \"../renderer/customRenderer.js\";\n\t * import { experimental_AstroContainer as AstroContainer } from \"astro/container\"\n\t *\n\t * const container = await AstroContainer.create();\n\t * container.addServerRenderer(reactRenderer);\n\t * container.addServerRenderer(vueRenderer);\n\t * container.addServerRenderer(\"customRenderer\", customRenderer);\n\t * ```\n\t *\n\t * @param options {object}\n\t * @param options.name The name of the renderer. The name **isn't** arbitrary, and it should match the name of the package.\n\t * @param options.renderer The server renderer exported by integration.\n\t */\n\tpublic addServerRenderer(options: AddServerRenderer): void {\n\t\tconst { renderer } = options;\n\t\tif (!renderer.check || !renderer.renderToStaticMarkup) {\n\t\t\tthrow new Error(\n\t\t\t\t\"The renderer you passed isn't valid. A renderer is usually an object that exposes the `check` and `renderToStaticMarkup` functions.\\n\" +\n\t\t\t\t\t\"Usually, the renderer is exported by a /server.js entrypoint e.g. `import renderer from '@astrojs/react/server.js'`\",\n\t\t\t);\n\t\t}\n\t\tif (isNamedRenderer(renderer)) {\n\t\t\tthis.#manifest.renderers.push({\n\t\t\t\tname: renderer.name,\n\t\t\t\tssr: renderer,\n\t\t\t});\n\t\t} else if ('name' in options) {\n\t\t\tthis.#manifest.renderers.push({\n\t\t\t\tname: options.name,\n\t\t\t\tssr: renderer,\n\t\t\t});\n\t\t} else {\n\t\t\tthrow new Error(\n\t\t\t\t'The renderer name must be provided when adding a server renderer that is not a named renderer.',\n\t\t\t);","sourceCodeStart":384,"sourceCodeEnd":420,"githubUrl":"https://github.com/withastro/astro/blob/3578d45d34226d63cff3d261c971c221de6794d2/packages/astro/src/container/index.ts#L384-L420","documentation":"`experimental_AstroContainer.addServerRenderer` validates that the passed renderer object exposes `check` and `renderToStaticMarkup` — the contract of an Astro server renderer. Missing either means you passed something else: the integration object, a client renderer, or the wrong export from the package.","triggerScenarios":"`addServerRenderer({ renderer: integration() })` (the integration, not its renderer); importing the package root (`@astrojs/react`) instead of `@astrojs/react/server.js`; passing a `{ entrypoint }` client-renderer shape; a hand-written renderer missing one of the two methods.","commonSituations":"Setting up container tests for framework components; older examples or blog posts showing different renderer shapes; wrapping/spreading a renderer and dropping its methods.","solutions":["Import the server entrypoint and pass it: `import renderer from '@astrojs/react/server.js'; container.addServerRenderer({ name: '@astrojs/react', renderer })`","If writing a custom renderer, implement both `check(Component)` and `renderToStaticMarkup(Component, props, slotted)`","Double-check you are not passing the integration object or a client renderer — only the `/server.js` export satisfies the shape"],"exampleFix":"// before\nimport react from '@astrojs/react';\ncontainer.addServerRenderer({ name: '@astrojs/react', renderer: react });\n\n// after\nimport renderer from '@astrojs/react/server.js';\ncontainer.addServerRenderer({ name: '@astrojs/react', renderer });","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function isServerRenderer(value) {\n  return (\n    !!value &&\n    typeof value.check === 'function' &&\n    typeof value.renderToStaticMarkup === 'function'\n  );\n}\n\nif (!isServerRenderer(renderer)) {\n  throw new TypeError('pass the /server.js export, not the integration or client renderer');\n}\ncontainer.addServerRenderer({ name, renderer });","tryCatchPattern":null,"preventionTips":["Import server renderers from the package's `/server.js` entrypoint (e.g. `@astrojs/react/server.js`)","When writing custom renderers, start from a type implementing `check` and `renderToStaticMarkup` so TypeScript catches the mistake","Keep a single test helper that registers renderers so wrong shapes fail in one place, not across many tests"],"tags":["container","renderers","api-misuse","testing","experimental"],"backgroundTag":"invalid-renderer-object","analyzedSha":"3578d45d34226d63cff3d261c971c221de6794d2","analyzedAt":"2026-08-18T18:48:03.901Z","contentChangedAt":"2026-08-18T18:48:03.901Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}