withastro/astro · error · AstroError

GetImageNotUsedOnServer

GetImageNotUsedOnServer

Error message

`getImage()` should only be used on the server. To use images on the client, render the `src` from `getImage()` during the server render, then pass it to the client for usage.

What it means

The Vite virtual module for `astro:assets` getImage generates two variants based on the Vite environment. When the importing module is in a client environment (isAstroServerEnvironment is false), the emitted `getImage` is a stub that throws GetImageNotUsedOnServer on call. This variant is the RESOLVED_VIRTUAL_GET_IMAGE_ID handler — the lightweight getImage-only export.

Source

Thrown at packages/astro/src/assets/vite-plugin-assets.ts:189

				},
			},
			load: {
				filter: {
					id: new RegExp(`^(${RESOLVED_VIRTUAL_MODULE_ID}|${RESOLVED_VIRTUAL_GET_IMAGE_ID})$`),
				},
				handler(id) {
					if (id === RESOLVED_VIRTUAL_GET_IMAGE_ID) {
						// Lightweight module exporting only getImage + imageConfig.
						// No component references (Image, Picture, Font) to avoid TDZ
						// errors when the content runtime and component pages are
						// bundled into the same prerender chunk (see #16036).
						const isServerEnvironment = isAstroServerEnvironment(this.environment);
						const getImageExport = isServerEnvironment
							? `import { getImage as getImageInternal } from "astro/assets";
								export const getImage = async (options) => await getImageInternal(options, imageConfig);`
							: `import { AstroError, AstroErrorData } from "astro/errors";
								export const getImage = async () => {
									throw new AstroError(
										AstroErrorData.GetImageNotUsedOnServer.message,
										AstroErrorData.GetImageNotUsedOnServer.hint,
									);
								};`;

						const assetQueryParams = settings.adapter?.client?.assetQueryParams
							? `new URLSearchParams(${JSON.stringify(
									Array.from(settings.adapter.client.assetQueryParams.entries()),
								)})`
							: 'undefined';

						return {
							code: `
								export const imageConfig = ${JSON.stringify(settings.config.image)};
								Object.defineProperty(imageConfig, 'assetQueryParams', {
									value: ${assetQueryParams},
									enumerable: false,
									configurable: true,

View on GitHub (pinned to d081033d5f)

Solutions

  1. Call getImage() during server render (frontmatter / .server modules / getStaticPaths) and pass the resulting src to the client.
  2. Pass the optimized src into client code via `define:vars` or a data attribute, not by calling getImage on the client.
  3. For pure client-side images, use a plain <img> tag instead of getImage.
  4. Confirm the module is not accidentally marked client-only (check import paths and Vite environment assignment).

Example fix

---
import { getImage } from 'astro:assets';
import logo from '../assets/logo.png';
const img = await getImage({ src: logo, width: 200 }); // server
---
<script define:vars={{ imgSrc: img.src }}>
  document.getElementById('logo').src = imgSrc; // client uses string
</script>
Defensive patterns

Strategy: type-guard

Validate before calling

// never call getImage in client code; gate calls
if (import.meta.env.SSR) {
  const img = await getImage({ src });
}

Type guard

const isServer = typeof import.meta !== 'undefined' && (import.meta as any).env?.SSR === true;

Prevention

When it happens

Trigger: Importing `getImage` from astro:assets (or the resolved virtual id) inside a module that Vite compiles for the client environment, then calling it at runtime. The client build replaces getImage with a thrower; calling it produces this error.

Common situations: Calling getImage() inside a `<script>` (client) or a framework client component; importing astro:assets getImage from a .client.ts island; rendering pipeline mis-classifying a module as client due to environment misconfiguration; using getImage in an event handler.

Related errors


AI-assisted analysis of withastro/astro@d081033d5f (2026-08-12). Data as JSON: /api/errors/54c2792129d833be. Report an issue: GitHub.