withastro/astro · error · Error
You tried to add the
Error message
You tried to add the ${name} client renderer, but its server renderer wasn't added. You must add the server renderer first. Use the `addServerRenderer` function. What it means
`addClientRenderer` registers the client entrypoint used for `client:*` hydration by looking up an already-registered server renderer with the same name in the container's manifest. No renderer with that name exists yet, so the client renderer would be unreachable — the call is rejected and the message points at `addServerRenderer`.
Solutions
- Register the server renderer first with the same name, then the client renderer
- Make both names identical — by convention the package name, e.g. `@astrojs/react`
- Load the client entrypoint from the package's `client.js` export (e.g. `import entrypoint from '@astrojs/react/client.js'`)
Example fix
// before
container.addClientRenderer({ name: '@astrojs/react', entrypoint });
container.addServerRenderer({ name: '@astrojs/react', renderer });
// after
container.addServerRenderer({ name: '@astrojs/react', renderer });
container.addClientRenderer({ name: '@astrojs/react', entrypoint }); Defensive patterns
Strategy: validation
Validate before calling
// track registrations yourself and enforce ordering in a helper
const registeredServerRenderers = new Set();
function addRendererPair(container, name, serverRenderer, clientEntrypoint) {
container.addServerRenderer({ name, renderer: serverRenderer });
registeredServerRenderers.add(name);
if (clientEntrypoint) {
if (!registeredServerRenderers.has(name)) {
throw new Error(`server renderer '${name}' must be registered first`);
}
container.addClientRenderer({ name, entrypoint: clientEntrypoint });
}
} Prevention
- Register server renderers before their client renderers — make one bootstrap function that does both in order
- Use the exact same string (the package name) for both addServerRenderer and addClientRenderer calls
- Load the client entrypoint from the package's `client.js` export rather than guessing paths
When it happens
Trigger: Calling `addClientRenderer({ name, entrypoint })` before `addServerRenderer({ name, renderer })`; using a name that does not exactly match the server renderer's name (missing `@scope/`, typo, different casing).
Common situations: Bootstrapping container tests that render hydrated components; copy-pasted setup where the two names drift apart ('react' vs '@astrojs/react'); ordering mistakes in test helpers.
Related errors
- The renderer name must be provided when adding a server…
- The renderer you passed isn't valid. A renderer is usually…
- Couldn't find component for route
- [astro:cache] Background revalidation failed for
- Could not find server component export
AI-assisted analysis of withastro/astro@3578d45d34 (2026-08-18).
Data as JSON: /api/errors/1158268204a44256.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/container/index.ts:452
*
* const container = await AstroContainer.create();
* container.addServerRenderer(reactRenderer);
* container.addClientRenderer({
* name: "@astrojs/react",
* entrypoint: "@astrojs/react/client.js"
* });
* ```
*
* @param options {object}
* @param options.name The name of the renderer. The name **isn't** arbitrary, and it should match the name of the package.
* @param options.entrypoint The entrypoint of the client renderer.
*/
public addClientRenderer(options: AddClientRenderer): void {
const { entrypoint, name } = options;
const rendererIndex = this.#manifest.renderers.findIndex((r) => r.name === name);
if (rendererIndex === -1) {
throw new Error(
'You tried to add the ' +
name +
" client renderer, but its server renderer wasn't added. You must add the server renderer first. Use the `addServerRenderer` function.",
);
}
const renderer = this.#manifest.renderers[rendererIndex];
renderer.clientEntrypoint = entrypoint;
this.#manifest.renderers[rendererIndex] = renderer;
}
// NOTE: we keep this private via TS instead via `#` so it's still available on the surface, so we can play with it.
// @ts-expect-error @ematipico: I plan to use it for a possible integration that could help people
private static async createFromManifest(
manifest: SSRManifest,
): Promise<experimental_AstroContainer> {
const container = new experimental_AstroContainer({
manifest,View on GitHub (pinned to 3578d45d34)