{"record":{"id":"7e1b862bc0e2a506","repo":"withastro/astro","slug":"app-entrypoint-must-default-export-an-object","errorCode":null,"errorMessage":"App entrypoint must default export an object.","messagePattern":"App entrypoint must default export an object\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/astro/src/toolbar/vite-plugin-dev-toolbar.ts","lineNumber":108,"sourceCode":"\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tlet app;\n\t\t\t\t\t\t\t\tif (typeof appDefinition === 'string') {\n\t\t\t\t\t\t\t\t\tapp = await importEntrypoint();\n\n\t\t\t\t\t\t\t\t\tif (typeof app !== 'object' || !app.id || !app.name) {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Apps must default export an object with an id, and a name.\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tapp = appDefinition;\n\n\t\t\t\t\t\t\t\t\tif (typeof app !== 'object' || !app.id || !app.name || !app.entrypoint) {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"Apps must be an object with an id, a name and an entrypoint.\");\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tconst loadedApp = await importEntrypoint();\n\n\t\t\t\t\t\t\t\t\tif (typeof loadedApp !== 'object') {\n\t\t\t\t\t\t\t\t\t\tthrow new Error(\"App entrypoint must default export an object.\");\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tapp = { ...app, ...loadedApp };\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn app;\n\t\t\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\t\t\tconsole.error(\\`Failed to load dev toolbar app from \\${entrypoint}: \\${err.message}\\`);\n\n\t\t\t\t\t\t\t\tif (import.meta.hot) {\n\t\t\t\t\t\t\t\timport.meta.hot.send('astro:devtoolbar:error:load', { entrypoint: entrypoint, error: err.message })\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn undefined;\n\t\t\t\t\t\t}","sourceCodeStart":90,"sourceCodeEnd":126,"githubUrl":"https://github.com/withastro/astro/blob/d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca/packages/astro/src/toolbar/vite-plugin-dev-toolbar.ts#L90-L126","documentation":"Thrown by the dev toolbar plugin when an app is registered in object form (with id/name/entrypoint), the entrypoint is successfully imported, but its default export is not an object. The toolbar merges `{ ...app, ...loadedApp }`, so the loaded entrypoint must contribute an object (typically containing the app's component/hook callbacks).","triggerScenarios":"The entrypoint module does `export default function MyComponent() {...}` or `export default class {...}` or has no default export (undefined), then the object-form registration triggers `typeof loadedApp !== 'object'` after `importEntrypoint()`. A default export of a string, number, or function also triggers it.","commonSituations":"Authoring a toolbar app entrypoint that default-exports a function or component instead of an object. Forgetting the `export default` keyword entirely (loadedApp is undefined). Refactoring an entrypoint from object-export to function-export without updating the registration form.","solutions":["Make the entrypoint default-export an object: `export default { id: 'myapp', name: 'My App', init() {}, ... }`.","If you intend the default export to be a function/component, switch the registration to the string form so only id/name are validated.","Verify there are no conditional or named-only exports masking the default export."],"exampleFix":"// before — entrypoint.ts\nexport default function App() {}\n// registration: { id, name, entrypoint: './entrypoint.ts' }\n\n// after\nexport default { id: 'myapp', name: 'My App', init(canvas) {} };","handlingStrategy":"validation","validationCode":"// In the entrypoint module's test:\nimport * as mod from './my-entrypoint.ts';\nif (typeof mod.default !== 'object' || mod.default === null) {\n  throw new Error('entrypoint must default-export a plain object');\n}","typeGuard":"function isAppExport(val): val is { id: string; name: string; [k: string]: unknown } {\n  return typeof val === 'object' && val !== null && typeof val.id === 'string' && typeof val.name === 'string';\n}","tryCatchPattern":null,"preventionTips":["Default-export a plain object from every toolbar app entrypoint.","Add an eslint rule or test that asserts the default export is an object literal.","When refactoring an entrypoint's export shape, update its registration form to match."],"tags":["dev-toolbar","configuration","modules"],"backgroundTag":null,"analyzedSha":"d081033d5fe8e8a68c4bbbad4af9d2deb9c74bca","analyzedAt":"2026-08-12T13:37:29.035Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}