withastro/astro · error · Error
Apps must default export an object with an id, and a name.
Error message
Apps must default export an object with an id, and a name.
What it means
Dev toolbar apps registered through an integration can be declared as a string path. In that form the toolbar imports the entrypoint module and requires its default export to be an object with at least id and name (plus lifecycle methods such as init). This error means the module at the entrypoint loaded fine but its default export is not an object or is missing id/name.
Solutions
- Make the entrypoint default-export an app object: export default { id: 'my-app', name: 'My App', init(ctx) {} }
- Check the dev toolbar API docs for your Astro version — the expected export shape changed across majors
- If the implementation lives in another file, re-export it as the default: export { default } from './impl.js'
Example fix
// before — src/toolbar/my-app.ts
export default function app() {
console.log('runs');
}
// after
export default {
id: 'my-app',
name: 'My App',
init(ctx) {
console.log('runs', ctx);
},
}; Defensive patterns
Strategy: validation
Validate before calling
// dev-time sanity check for a string-form toolbar app entrypoint
const app = (await import('./my-app.js')).default;
if (typeof app !== 'object' || app === null || !app.id || !app.name) {
throw new TypeError('Toolbar app entrypoint must default-export { id, name, ... }');
} Type guard
const isToolbarApp = (v: unknown): v is { id: string; name: string } =>
typeof v === 'object' && v !== null && typeof (v as any).id === 'string' && typeof (v as any).name === 'string'; Prevention
- Default-export an app object ({ id, name, init }) from every toolbar entrypoint — never a bare function
- Follow the toolbar app example in the Astro docs matching your major version
- When splitting files, re-export the app object as default: export { default } from './impl.js'
When it happens
Trigger: Registering a toolbar app as a string entrypoint whose module default-exports a function, class, or nothing; default-exporting { name: 'X' } without id; the entrypoint re-exporting from another module that has no default export.
Common situations: Copying toolbar app examples from older Astro docs where the default export was a component factory; splitting an app across files and forgetting to re-export the app object as default.
Related errors
- App entrypoint must default export an object.
- Apps must be an object with an id, a name and an entrypoint.
- 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/6a274a24aebb7c16.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/toolbar/vite-plugin-dev-toolbar.ts:96
`safeLoadPlugin(${JSON.stringify(
plugin,
)}, async () => (await import(${JSON.stringify(
typeof plugin === 'string' ? plugin : plugin.entrypoint.toString(),
)})).default, ${JSON.stringify(
typeof plugin === 'string' ? plugin : plugin.entrypoint.toString(),
)})`,
)
.join(',')}]));
};
async function safeLoadPlugin(appDefinition, importEntrypoint, entrypoint) {
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;View on GitHub (pinned to 52e6c34790)