{"record":{"id":"7ddcc987e819aca1","repo":"halo-dev/halo","slug":"pluginmodule-routes-must-be-an-array","errorCode":null,"errorMessage":"PluginModule.routes must be an array.","messagePattern":"PluginModule\\.routes must be an array\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"ui/src/setup/setupModules.ts","lineNumber":671,"sourceCode":"      componentOwners\n    );\n  }\n}\n\nfunction preparePluginModule(\n  module: PluginModule,\n  registration: UiProviderRegistration,\n  report: (\n    registration: UiProviderRegistration,\n    stage: UiPluginFailureStage,\n    error: unknown\n  ) => void\n) {\n  if (module.components && !isRecord(module.components)) {\n    throw new TypeError(\"PluginModule.components must be an object.\");\n  }\n  if (module.routes && !Array.isArray(module.routes)) {\n    throw new TypeError(\"PluginModule.routes must be an array.\");\n  }\n  if (module.ucRoutes && !Array.isArray(module.ucRoutes)) {\n    throw new TypeError(\"PluginModule.ucRoutes must be an array.\");\n  }\n  if (module.formkit && !isRecord(module.formkit)) {\n    throw new TypeError(\"PluginModule.formkit must be an object.\");\n  }\n  if (module.extensionPoints && !isRecord(module.extensionPoints)) {\n    throw new TypeError(\"PluginModule.extensionPoints must be an object.\");\n  }\n  resetRouteMetaAndWrapChunks(module.routes, false, registration, report);\n  resetRouteMetaAndWrapChunks(module.ucRoutes, false, registration, report);\n}\n\nfunction resetRouteMetaAndWrapChunks(\n  routes: RouteRecordRaw[] | RouteRecordAppend[] | undefined,\n  core: boolean,\n  registration?: UiProviderRegistration,","sourceCodeStart":653,"sourceCodeEnd":689,"githubUrl":"https://github.com/halo-dev/halo/blob/d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8/ui/src/setup/setupModules.ts#L653-L689","documentation":"Thrown by preparePluginModule when module.routes is present but not an array. routes must be RouteRecordRaw[] | RouteRecordAppend[] so Halo can iterate and register console routes (with meta/chunk wrapping). A non-array value would break the route registration loop, so the host throws a TypeError before touching the router.","triggerScenarios":"A plugin module returns { routes: { path: '/x' } } (a single object) or { routes: 'x' } during activation; preparePluginModule reads module.routes and Array.isArray fails.","commonSituations":"Plugin author returns one route object instead of an array; merges routes from a nested object; a typo assigns a string.","solutions":["Wrap the route(s) in an array: { routes: [{ path: '/x', component: X }] }.","Omit routes if the plugin registers no console routes.","Typecheck the plugin module against PluginModule before release."],"exampleFix":"// before\nexport default definePluginModule({ routes: { name: \"foo\", path: \"/foo\", component: Foo } });\n\n// after\nexport default definePluginModule({ routes: [{ name: \"foo\", path: \"/foo\", component: Foo }] });","handlingStrategy":"type-guard","validationCode":"function assertRoutesShape(module: { routes?: unknown }) {\n  if (module.routes && !Array.isArray(module.routes)) {\n    throw new TypeError(\"PluginModule.routes must be an array.\");\n  }\n}","typeGuard":"function isRouteArray(value: unknown): value is unknown[] {\n  return Array.isArray(value);\n}","tryCatchPattern":null,"preventionTips":["Always wrap routes in an array literal, even for a single route.","Typecheck the plugin module with vue-tsc.","Add a spec that asserts Array.isArray(module.routes)."],"tags":["runtime","plugin-module","routes","vue-router","validation"],"backgroundTag":null,"analyzedSha":"d2f5165f9c8f055ffcb3fa9c3f4032821a7b68c8","analyzedAt":"2026-08-14T00:18:38.915Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}