withastro/astro · error · Error

App entrypoint must default export an object.

Error message

App entrypoint must default export an object.

What it means

For object-form dev toolbar apps, Astro loads the entrypoint module and merges its default export into the app definition (app = { ...app, ...loadedApp }). That default export must be an object, typically carrying lifecycle hooks like init. If the entrypoint default-exports a function, class, primitive, or nothing at all, this error is thrown.

Solutions

  1. Change the entrypoint to default-export a plain object: export default { init(ctx) { ... } }
  2. Keep any function-based logic inside the object's init hook rather than exporting the function itself

Example fix

// before — src/toolbar/my-app.ts (used as entrypoint)
export default () => {
	/* app logic */
};

// after
export default {
	init(ctx) {
		/* app logic */
	},
};
Defensive patterns

Strategy: validation

Validate before calling

// verify an object-form entrypoint default-exports an object before registering
const loaded = (await import('./my-app.js')).default;
if (typeof loaded !== 'object' || loaded === null) {
	throw new TypeError('Toolbar app entrypoint must default-export an object (e.g. { init(ctx) {} })');
}

Type guard

const isToolbarEntrypointExport = (v: unknown): v is Record<string, unknown> =>
	typeof v === 'object' && v !== null;

Prevention

When it happens

Trigger: defineToolbarApp({ id, name, entrypoint }) where the entrypoint file has export default () => {...} instead of export default { init() {...} }; an entrypoint with only named exports; a default export of null.

Common situations: Converting a string-form app to object form while leaving a function-style default export; bundler/re-export setups that drop the default export.

Related errors


AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18). Data as JSON: /api/errors/7e1b862bc0e2a506. Report an issue: GitHub.

Appendix: source

Thrown at packages/astro/src/toolbar/vite-plugin-dev-toolbar.ts:108

							try {
								let app;
								if (typeof appDefinition === 'string') {
									app = await importEntrypoint();

									if (typeof app !== 'object' || !app.id || !app.name) {
										throw new Error("Apps must default export an object with an id, and a name.");
									}
								} else {
									app = appDefinition;

									if (typeof app !== 'object' || !app.id || !app.name || !app.entrypoint) {
										throw new Error("Apps must be an object with an id, a name and an entrypoint.");
									}

									const loadedApp = await importEntrypoint();

									if (typeof loadedApp !== 'object') {
										throw new Error("App entrypoint must default export an object.");
									}

									app = { ...app, ...loadedApp };
								}

								return app;
							} catch (err) {
								console.error(\`Failed to load dev toolbar app from \${entrypoint}: \${err.message}\`);

								if (import.meta.hot) {
								import.meta.hot.send('astro:devtoolbar:error:load', { entrypoint: entrypoint, error: err.message })
								}

								return undefined;
							}

							return undefined;
						}

View on GitHub (pinned to 52e6c34790)