parcel-bundler/parcel · error · ThrowableDiagnostic

Unsupported custom SVGO plugin.

Error message

Unsupported custom SVGO plugin.

What it means

Thrown by @parcel/utils svgo plugin normalization when a Parcel/SVGO config supplies a custom SVGO plugin as a function (plugin.fn is a function, or the plugin entry itself is a function). Parcel only supports SVGO's built-in named plugins, not user-supplied JS function plugins, so it emits a diagnostic via throwDiagnostic with a code frame pointing at the offending config location.

Source

Thrown at packages/core/utils/src/svgo.js:136

          typeof params === 'object' &&
          typeof params?.overrides === 'object' &&
          params.overrides
        ) {
          for (let key in params.overrides) {
            result[key] = params.overrides[key];
          }
        }
      } else if (typeof name === 'string') {
        result[(name: any)] = params || false;
      }
    }
  }

  return result;
}

async function throwDiagnostic(message, filePath, jsonPath, fs, hint) {
  throw new ThrowableDiagnostic({
    diagnostic: {
      message: message,
      codeFrames: [
        {
          filePath: filePath,
          codeHighlights:
            path.extname(filePath) === '' || path.extname(filePath) === '.json'
              ? generateJSONCodeHighlights(
                  await fs.readFile(filePath, 'utf8'),
                  [
                    {
                      key: jsonPath,
                    },
                  ],
                )
              : [],
        },
      ],

View on GitHub (pinned to 59484858a1)

Solutions

  1. Replace function plugins with the equivalent built-in named SVGO plugin (e.g. 'removeViewBox', 'mergePaths') and configure via params.
  2. If you need custom transformation, pre-process the SVG with a separate tool/step before Parcel.
  3. Remove the offending plugin entry from the config file highlighted in the diagnostic.
  4. Consult SVGO's plugin list and map your custom function to the closest built-in.

Example fix

// before — .svgo.json or parcel svgo config
{
  "plugins": [{ "name": "mine", "fn": () => ({}) }]
}

// after — use a built-in named plugin
{
  "plugins": ["preset-default", "removeViewBox"]
}
Defensive patterns

Strategy: validation

Validate before calling

// Reject function-based SVGO plugins before handing config to Parcel.
function assertNoFunctionPlugins(svgoConfig) {
  const plugins = svgoConfig?.plugins ?? [];
  for (const p of plugins) {
    if (typeof p === 'function' || (p && typeof p.fn === 'function')) {
      throw new Error('Parcel does not support custom function SVGO plugins; use named built-ins.');
    }
  }
}

Type guard

type NamedPlugin = string | { name: string; params?: object };
function isNamedSVGOPlugin(p: unknown): p is NamedPlugin {
  return typeof p === 'string' || (typeof p === 'object' && p !== null && typeof (p as any).name === 'string');
}

Prevention

When it happens

Trigger: Authoring a .parcelrc or SVG optimizer config whose svgo.plugins array contains an inline function plugin (e.g. `plugins: [() => {...}]` or `plugins: [{name:'x', fn: () => ...}]`) instead of a named built-in plugin string or name+params object.

Common situations: Porting a raw SVGO config (which allows custom plugins) into Parcel; tutorials suggesting function-based SVGO plugins; upgrading SVGO version where the plugin shape changed.

Related errors


AI-assisted analysis of parcel-bundler/parcel@59484858a1 (2026-08-13). Data as JSON: /api/errors/c4017e64937fbbf2. Report an issue: GitHub.