{"record":{"id":"bb8d0e81a757b1d0","repo":"parcel-bundler/parcel","slug":"plugin-pluginname-is-not-a-valid-parcel-plugin","errorCode":null,"errorMessage":"Plugin ${pluginName} is not a valid Parcel plugin, should export an instance of a Parcel plugin ex. \"export default new Reporter({ ... })\".","messagePattern":"Plugin (.+?) is not a valid Parcel plugin, should export an instance of a Parcel plugin ex\\. \"export default new Reporter\\((.+?)\\)\"\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/core/src/loadParcelPlugin.js","lineNumber":236,"sourceCode":"                ]),\n              },\n            ],\n          },\n        });\n      }\n    }\n  }\n\n  let plugin = await options.packageManager.require(pluginName, resolveFrom, {\n    shouldAutoInstall: options.shouldAutoInstall,\n  });\n  plugin = plugin.default ? plugin.default : plugin;\n  if (!plugin) {\n    throw new Error(`Plugin ${pluginName} has no exports.`);\n  }\n  plugin = plugin[CONFIG];\n  if (!plugin) {\n    throw new Error(\n      `Plugin ${pluginName} is not a valid Parcel plugin, should export an instance of a Parcel plugin ex. \"export default new Reporter({ ... })\".`,\n    );\n  }\n  return {\n    plugin,\n    version: nullthrows(pkg).version,\n    resolveFrom: toProjectPath(options.projectRoot, resolveFrom),\n    range,\n  };\n}\n","sourceCodeStart":218,"sourceCodeEnd":247,"githubUrl":"https://github.com/parcel-bundler/parcel/blob/59484858a1a0bcbb71f74088956bb437a2db6505/packages/core/core/src/loadParcelPlugin.js#L218-L247","documentation":"After unwrapping the default export, Parcel looks for the internal `CONFIG` symbol that marks an object as a genuine Parcel plugin instance (created via `new Reporter()`, `new Transformer()`, etc.). If the module exports a plain object/function/array instead, the `CONFIG` lookup returns falsy and Parcel reports that this is not a valid plugin, with an example of the correct shape.","triggerScenarios":"A plugin module's default export is a plain config object, a class, or a function rather than an instance produced by a Parcel plugin class.","commonSituations":"Plugin author returns a raw object literal `export default { transform() {...} }` instead of wrapping it in `new Transformer({...})`.","solutions":["Wrap the plugin definition in the appropriate class from `@parcel/plugin` (e.g. `new Reporter({...})`).","Make sure the instance is the default export.","If subclassing, ensure you call the base constructor so the `CONFIG` symbol is set."],"exampleFix":"// before\nexport default { async transform({asset}) { return [asset]; } };\n\n// after\nimport {Transformer} from '@parcel/plugin';\nexport default new Transformer({ async transform({asset}) { return [asset]; } });","handlingStrategy":"type-guard","validationCode":"// Confirm the export is a Parcel plugin instance (has CONFIG).\nconst exp = mod.default ?? mod;\nif (!exp || !exp[CONFIG]) {\n  throw new Error(`${name} is not a Parcel plugin instance`);\n}","typeGuard":"function isParcelPluginInstance(exp: any): boolean {\n  return Boolean(exp && exp[CONFIG]);\n}","tryCatchPattern":null,"preventionTips":["Construct plugin instances with classes from @parcel/plugin.","Don't return plain config objects as the default export.","Add a unit test asserting `default[CONFIG]` exists."],"tags":["plugin","authoring","exports"],"backgroundTag":null,"analyzedSha":"59484858a1a0bcbb71f74088956bb437a2db6505","analyzedAt":"2026-08-13T04:06:35.925Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}