halo-dev/halo · error · TypeError
PluginModule.formkit must be an object.
Error message
PluginModule.formkit must be an object.
What it means
Thrown by preparePluginModule when module.formkit is present but not a plain object (isRecord fails — array, primitive, function, null). formkit must be a PluginFormKit record mapping input names to FormKit definitions so Halo can register custom FormKit inputs. A wrong shape would corrupt FormKit config, so activation throws a TypeError.
Source
Thrown at ui/src/setup/setupModules.ts:677
module: PluginModule,
registration: UiProviderRegistration,
report: (
registration: UiProviderRegistration,
stage: UiPluginFailureStage,
error: unknown
) => void
) {
if (module.components && !isRecord(module.components)) {
throw new TypeError("PluginModule.components must be an object.");
}
if (module.routes && !Array.isArray(module.routes)) {
throw new TypeError("PluginModule.routes must be an array.");
}
if (module.ucRoutes && !Array.isArray(module.ucRoutes)) {
throw new TypeError("PluginModule.ucRoutes must be an array.");
}
if (module.formkit && !isRecord(module.formkit)) {
throw new TypeError("PluginModule.formkit must be an object.");
}
if (module.extensionPoints && !isRecord(module.extensionPoints)) {
throw new TypeError("PluginModule.extensionPoints must be an object.");
}
resetRouteMetaAndWrapChunks(module.routes, false, registration, report);
resetRouteMetaAndWrapChunks(module.ucRoutes, false, registration, report);
}
function resetRouteMetaAndWrapChunks(
routes: RouteRecordRaw[] | RouteRecordAppend[] | undefined,
core: boolean,
registration?: UiProviderRegistration,
report?: (
registration: UiProviderRegistration,
stage: UiPluginFailureStage,
error: unknown
) => void
) {View on GitHub (pinned to d2f5165f9c)
Solutions
- Return formkit as an object keyed by input name: { formkit: { myInput: { type: 'input' } } }.
- Omit the field if the plugin ships no custom FormKit inputs.
- Typecheck the plugin module against PluginModule.
Example fix
// before
export default definePluginModule({ formkit: [{ type: "input", name: "myInput" }] });
// after
export default definePluginModule({ formkit: { myInput: { type: "input" } } }); Defensive patterns
Strategy: type-guard
Validate before calling
function assertFormkitShape(module: { formkit?: unknown }) {
if (module.formkit && (typeof module.formkit !== "object" || module.formkit === null || Array.isArray(module.formkit))) {
throw new TypeError("PluginModule.formkit must be an object.");
}
} Type guard
function isFormkitRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
} Prevention
- Return formkit as an object keyed by input name.
- Typecheck the plugin module with vue-tsc.
- Omit formkit when the plugin ships no custom inputs.
When it happens
Trigger: A plugin module returns { formkit: [...] } (array) or { formkit: null } or a function during activation; preparePluginModule's isRecord(module.formkit) check fails.
Common situations: Author mistakes formkit for an array of definitions; assigns a single schema; a generator returns the wrong shape.
Related errors
- PluginModule.components must be an object.
- PluginModule.routes must be an array.
- PluginModule.ucRoutes must be an array.
- Cannot restore a replaced route under an anonymous parent re
- No permission to upload attachment
AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14).
Data as JSON: /api/errors/241eff7faae2016b.
Report an issue: GitHub.