withastro/astro · error · Error

Invalid component export path: ${componentExport}

Error message

Invalid component export path: ${componentExport}

What it means

When hydrating an island, Astro resolves the component export path from the `component-export` attribute. It forbids the prototype-pollution keys `__proto__`, `constructor`, and `prototype` (the `FORBIDDEN_COMPONENT_EXPORT_KEYS` set) anywhere in the export path, and also requires each dotted segment to be an own property of a real object/function. Any violation throws a plain `Invalid component export path` Error.

Source

Thrown at packages/astro/src/runtime/server/astro-island.ts:160

			if (Astro[directive] === undefined) {
				window.addEventListener(`astro:${directive}`, () => this.start(), { once: true });
				return;
			}
			try {
				await Astro[directive]!(
					async () => {
						const rendererUrl = this.getAttribute('renderer-url');
						try {
							const [componentModule, { default: hydrator }] = await Promise.all([
								this.importWithRetry(this.getAttribute('component-url')!),
								rendererUrl
									? this.importWithRetry(rendererUrl)
									: Promise.resolve({ default: () => () => {} }),
							]);
							const componentExport = this.getAttribute('component-export') || 'default';
							if (!componentExport.includes('.')) {
								if (FORBIDDEN_COMPONENT_EXPORT_KEYS.has(componentExport)) {
									throw new Error(`Invalid component export path: ${componentExport}`);
								}
								this.Component = componentModule[componentExport];
							} else {
								this.Component = componentModule;
								for (const part of componentExport.split('.')) {
									if (
										FORBIDDEN_COMPONENT_EXPORT_KEYS.has(part) ||
										!this.Component ||
										(typeof this.Component !== 'object' && typeof this.Component !== 'function') ||
										!Object.hasOwn(this.Component, part)
									) {
										throw new Error(`Invalid component export path: ${componentExport}`);
									}
									this.Component = this.Component[part];
								}
							}
							this.hydrator = hydrator;
							return this.hydrate;

View on GitHub (pinned to d081033d5f)

Solutions

  1. Regenerate the page so the island's `component-export` attribute reflects a real, allowed named export.
  2. Ensure the referenced component is exported under a plain named (or default) export that isn't a prototype key.
  3. If serving cached/CDN HTML, purge the cache so stale or tampered island attributes are replaced.
  4. Treat unexpected occurrences as a possible XSS/prototype-pollution probe and audit the page source.

Example fix

// before — island HTML references a forbidden export
<astro-island component-export="__proto__" ...></astro-island>

// after — reference a real named export
<astro-island component-export="default" ...></astro-island>
Defensive patterns

Strategy: validation

Validate before calling

const FORBIDDEN = new Set(['__proto__','constructor','prototype']);
function isSafeComponentExport(exportPath) {
  return exportPath.split('.').every(seg =>
    seg.length > 0 && !FORBIDDEN.has(seg) && /^[A-Za-z_$][\w$]*$/.test(seg)
  );
}

Type guard

function isSafeExportPath(exportPath) {
  const FORBIDDEN = new Set(['__proto__','constructor','prototype']);
  return typeof exportPath === 'string' &&
    exportPath.length > 0 &&
    exportPath.split('.').every(seg => seg && !FORBIDDEN.has(seg));
}

Try / catch

null

Prevention

When it happens

Trigger: A hydrated island's serialized HTML carries a `component-export` attribute equal to (or containing a dotted segment of) `__proto__`, `constructor`, or `prototype`; or a dotted path segment that isn't an own enumerable property of the resolved module/object.

Common situations: Tampered or hand-edited island HTML; a build artifact where the export name resolved to a forbidden key; an attempt to traverse the module prototype chain via the export path; desync between the module's exports and the recorded `component-export` after a refactor.

Related errors


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