withastro/astro · error · Error
Apps must be an object with an id, a name and an entrypoint.
Error message
Apps must be an object with an id, a name and an entrypoint.
What it means
When a dev toolbar app is registered as an inline object (defineToolbarApp with an object), Astro requires three fields: id, name, and entrypoint (the path/URL of the app's client code, which is loaded and merged into the definition). This error is thrown at load time when any of the three is missing from the app object.
Solutions
- Provide all three required fields: defineToolbarApp({ id: 'my-app', name: 'My App', entrypoint: '/src/toolbar/my-app.ts' })
- If you only have a module path, register the string form instead and default-export the app object from that module
Example fix
// before
export default defineToolbarApp({ id: 'my-app', name: 'My App' });
// after
export default defineToolbarApp({
id: 'my-app',
name: 'My App',
entrypoint: '/src/toolbar/my-app.ts',
}); Defensive patterns
Strategy: validation
Validate before calling
const app = { id: 'my-app', name: 'My App', entrypoint: '/src/toolbar/my-app.ts' };
const missing = ['id', 'name', 'entrypoint'].filter((k) => !app[k]);
if (missing.length) throw new Error(`Toolbar app is missing fields: ${missing.join(', ')}`);
export default defineToolbarApp(app); Type guard
type ToolbarAppDef = { id: string; name: string; entrypoint: string };
const isToolbarAppDef = (v: unknown): v is ToolbarAppDef =>
typeof v === 'object' && v !== null &&
typeof (v as any).id === 'string' &&
typeof (v as any).name === 'string' &&
typeof (v as any).entrypoint === 'string'; Prevention
- Object-form toolbar apps always need id, name, AND entrypoint — check all three before registering
- Use TypeScript so a missing field fails at compile time, not in the dev toolbar
- Copy the object shape from a working first-party toolbar app
When it happens
Trigger: defineToolbarApp({ id: 'my-app', name: 'My App' }) without entrypoint; passing { id, entrypoint } without a human-readable name; typos in field names (appId instead of id) so the required keys read as missing.
Common situations: Writing a first toolbar integration from a partial example; renaming fields when copying another app's definition.
Related errors
- App entrypoint must default export an object.
- Apps must default export an object with an id, and a name.
- More than one JSX renderer is enabled. This will lead to…
- More than one JSX renderer is enabled. This will lead to…
- More than one JSX renderer is enabled. This will lead to…
AI-assisted analysis of withastro/astro@52e6c34790 (2026-08-18).
Data as JSON: /api/errors/9de6456ba99020af.
Report an issue: GitHub.
Appendix: source
Thrown at packages/astro/src/toolbar/vite-plugin-dev-toolbar.ts:102
)})`,
)
.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;
} 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 })
}View on GitHub (pinned to 52e6c34790)