composer/composer · error · PluginBlockedException

contains a Composer plugin which is blocked by your…

Error message

{package}{global_suffix} contains a Composer plugin which is blocked by your allow-plugins config. You may add it to the list if you consider it safe.
You can run "composer {global_prefix}config --no-plugins allow-plugins.{package} [true|false]" to enable it (true) or disable it explicitly and suppress this exception (false)
See https://getcomposer.org/allow-plugins

What it means

Thrown by PluginManager as a PluginBlockedException when a Composer plugin package is not explicitly allowed (or disallowed) in the 'config.allow-plugins' map of composer.json and the user did not authorize it interactively (or the session is non-interactive). Since Composer 2.2 plugins run only when whitelisted, to prevent arbitrary code execution from dependencies. The message tells you exactly how to allow or block it via config.

Solutions

  1. Run the exact command from the message: composer config --no-plugins allow-plugins.<package> true to allow it (or false to suppress).
  2. For global plugins, prefix with 'global': composer global config --no-plugins allow-plugins.<package> true.
  3. Add the full allow-plugins map to composer.json config and commit it so CI is reproducible.
  4. In CI, ensure the runner is non-interactive only AFTER allow-plugins is configured, or set COMPOSER_NO_INTERACTION=1 after committing the list.

Example fix

// before
{ "config": {} }
// after
{
  "config": {
    "allow-plugins": {
      "phpstan/extension-installer": true,
      "dealerdirect/phpcodesniffer-composer-installer": true
    }
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check allow-plugins config before running install in CI
$pkg = 'phpstan/extension-installer';
$cfg = json_decode(file_get_contents('composer.json'), true);
$allowed = $cfg['config']['allow-plugins'] ?? [];
if (!array_key_exists($pkg, $allowed)) {
    // explicitly allow or disallow to avoid the interactive block
    $cfg['config']['allow-plugins'][$pkg] = true;
    file_put_contents('composer.json', json_encode($cfg, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));
}

Type guard

function pluginIsDecided(string $pkg, array $config): bool {
    return array_key_exists($pkg, $config['config']['allow-plugins'] ?? []);
}

Try / catch

try {
    // run composer operation
} catch (\Composer\Plugin\PluginBlockedException $e) {
    // parse package name, prompt user, then run the suggested config command
    throw $e;
}

Prevention

When it happens

Trigger: During dependency resolution/install, PluginManager::arePluginsAllowed() finds the package missing from allow-plugins; the interactive prompt (y/n/d/?) either was never shown (non-interactive) or the user exhausted attempts. Reached via PluginManager::loadRepository() / registerPackage() when a package provides Composer\Plugin\PluginInterface.

Common situations: Upgrading to Composer 2.2+ where allow-plugins is required; CI runs (non-interactive) where a new plugin dependency triggers the block; a fresh 'composer require' of a package that ships a plugin (e.g. composer-require-fixer, phpstan/extension-installer).

Related errors


AI-assisted analysis of composer/composer@c435d285c9 (2026-08-07). Data as JSON: /api/errors/4f6690f7c1df141f. Report an issue: GitHub.

Appendix: source

Thrown at src/Composer/Plugin/PluginManager.php:821

                        return $allow;

                    case '?':
                    default:
                        $attempts++;
                        $this->io->writeError([
                            'y - add package to allow-plugins in composer.json and let it run immediately',
                            'n - add package (as disallowed) to allow-plugins in composer.json to suppress further prompts',
                            'd - discard this, do not change composer.json and do not allow the plugin to run',
                            '? - print help',
                        ]);
                        break;
                }
            }
        } elseif ($optional) {
            return false;
        }

        throw new PluginBlockedException(
            $package.($isGlobalPlugin || $this->runningInGlobalDir ? ' (installed globally)' : '').' contains a Composer plugin which is blocked by your allow-plugins config. You may add it to the list if you consider it safe.'.PHP_EOL.
            'You can run "composer '.($isGlobalPlugin || $this->runningInGlobalDir ? 'global ' : '').'config --no-plugins allow-plugins.'.$package.' [true|false]" to enable it (true) or disable it explicitly and suppress this exception (false)'.PHP_EOL.
            'See https://getcomposer.org/allow-plugins'
        );
    }
}

View on GitHub (pinned to c435d285c9)