composer/composer · error · InvalidArgumentException

Script "%s" is not defined in this package

Error message

Script "%s" is not defined in this package

What it means

Thrown when the requested script has no registered listeners — i.e. it is not defined under `scripts` in composer.json (and no plugin handles it). hasEventListeners() returns false, so dispatch would be a no-op and Composer rejects it instead. It is an \InvalidArgumentException.

Source

Thrown at src/Composer/Command/RunScriptCommand.php:125

        }

        $script = $input->getArgument('script');
        if ($script === null) {
            throw new \RuntimeException('Missing required argument "script"');
        }

        if (!in_array($script, $this->scriptEvents)) {
            if (defined('Composer\Script\ScriptEvents::'.str_replace('-', '_', strtoupper($script)))) {
                throw new \InvalidArgumentException(sprintf('Script "%s" cannot be run with this command', $script));
            }
        }

        $composer = $this->requireComposer();
        $devMode = $input->getOption('dev') || !$input->getOption('no-dev');
        $event = new ScriptEvent($script, $composer, $this->getIO(), $devMode);
        $hasListeners = $composer->getEventDispatcher()->hasEventListeners($event);
        if (!$hasListeners) {
            throw new \InvalidArgumentException(sprintf('Script "%s" is not defined in this package', $script));
        }

        $args = $input->getArgument('args');

        if (null !== $timeout = $input->getOption('timeout')) {
            if (!ctype_digit($timeout)) {
                throw new \RuntimeException('Timeout value must be numeric and positive if defined, or 0 for forever');
            }
            // Override global timeout set before in Composer by environment or config
            ProcessExecutor::setTimeout((int) $timeout);
        }

        Platform::putEnv('COMPOSER_DEV_MODE', $devMode ? '1' : '0');

        return $composer->getEventDispatcher()->dispatchScript($script, $devMode, $args);
    }

    protected function listScripts(OutputInterface $output): int

View on GitHub (pinned to c435d285c9)

Solutions

  1. List defined scripts with `composer run-script --list` and use an exact name.
  2. Add the script to composer.json under `scripts` if it should exist.
  3. Confirm you are in the project root that owns the composer.json defining the script.
  4. Watch for case and hyphen vs underscore mismatches in the name.

Example fix

// before
composer run-script tesst
// after (after `composer run-script --list`)
composer run-script test
Defensive patterns

Strategy: validation

Validate before calling

$data = json_decode((string) file_get_contents(getcwd() . '/composer.json'), true);
$scripts = array_keys($data['scripts'] ?? []);
if (!in_array($name, $scripts, true)) {
    fwrite(STDERR, "Script '$name' is not defined. Defined: " . implode(', ', $scripts) . "\n");
    exit(1);
}

Type guard

function scriptIsDefined(string $composerJson, string $name): bool\n{\n    $data = json_decode((string) file_get_contents($composerJson), true);\n    return is_array($data) && isset($data['scripts'][$name]);\n}

Try / catch

try {\n    // run `composer run-script <name>`\n} catch (\InvalidArgumentException $e) {\n    if (str_contains($e->getMessage(), 'is not defined in this package')) {\n        // list scripts, fix the name, retry\n    }\n}

Prevention

When it happens

Trigger: Running `composer run-script <name>` where <name> is neither a custom script in composer.json `scripts` nor an event with plugin listeners (RunScriptCommand.php:123-125).

Common situations: Typo in script name; running in the wrong project (no composer.json or different one); script was removed/renamed; copy-paste from a tutorial whose script keys differ.

Related errors


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