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
- Change the entrypoint to default-export a plain object: export default { init(ctx) { ... } }
- 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
- Object-form entries merge the entrypoint's default export into the app — keep that export a plain object with hooks like init
- Do not default-export functions, classes, or primitives from an entrypoint used via defineToolbarApp
- Test the toolbar app by running the dev server before shipping the integration
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
- Apps must be an object with an id, a name and an entrypoint.
- Apps must default export an object with an id, and a name.
- Integration has an unnamed renderer.
- Integration is injecting a type that does not end with
- Integration " " conflicts with " ". You can only configure…
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)