composer/composer · error · InvalidArgumentException

Unknown action "{action}". Use add-source.

Error message

Unknown action "{action}". Use add-source.

What it means

Thrown by `composer policy` (PolicyCommand.php:122, the `default` switch arm) when the required `action` argument is anything other than `add-source`. The command currently supports only one sub-action; any other value (including typos or plausible-but-unimplemented actions like `remove`, `list`, `enable`) lands in the default arm and is rejected with an `InvalidArgumentException`.

Source

Thrown at src/Composer/Command/PolicyCommand.php:122

                foreach ($currentSources as $existing) {
                    if (is_array($existing)
                        && ($existing['type'] ?? null) === $sourceConfig['type']
                        && ($existing['url'] ?? null) === ($sourceConfig['url'] ?? null)
                    ) {
                        $this->getIO()->write('<info>Source '.$sourceConfig['url'].' already present in policy '.$listName.'</info>');

                        return 0;
                    }
                }

                $currentSources[] = $sourceConfig;
                $this->configSource->addConfigSetting('policy.'.$listName.'.sources', $currentSources);

                return 0;

            default:
                throw new \InvalidArgumentException('Unknown action "'.$action.'". Use add-source.');
        }
    }

    private function assertCustomListName(string $name): void
    {
        if (in_array($name, PolicyConfig::BUILTIN_LIST_NAMES, true)) {
            throw new \RuntimeException('Built-in dependency policy "'.$name.'" does not support sources. Use `composer config policy.'.$name.'.<field>` to configure it.');
        }

        $error = PolicyConfig::getFutureReservedListNameError($name);
        if ($error !== null) {
            throw new \RuntimeException($error);
        }

        if ($name === '' || strpos($name, '.') !== false) {
            throw new \RuntimeException('Invalid dependency policy name "'.$name.'".');
        }
    }

View on GitHub (pinned to 6ffc117740)

Solutions

  1. Use the only supported action: `composer policy add-source <name> <type> <url>`.
  2. Check the exact spelling — it is `add-source` with a hyphen, not `addsource` or `add_source`.
  3. Run `composer policy --help` to list the accepted action value for your Composer build.

Example fix

// before
composer policy remove my-policy
// after
composer policy add-source my-policy url https://example.org/pkgs.json
Defensive patterns

Strategy: validation

Validate before calling

$allowedActions = ['add-source'];
if (!in_array(strtolower($action), $allowedActions, true)) {
    fwrite(STDERR, 'Unknown action. Supported: ' . implode(', ', $allowedActions) . PHP_EOL);
    exit(2);
}

Type guard

function isSupportedPolicyAction(string $action): bool {
    return in_array(strtolower($action), ['add-source'], true);
}

Prevention

When it happens

Trigger: Running `composer policy remove my-policy`, `composer policy list`, `composer policy show`, or any misspelling such as `composer policy addsource` or `composer policy add_source`. The `action` argument is `REQUIRED` so it cannot be omitted, but it is not constrained to a value-set at the input layer — only validated inside `execute()`.

Common situations: Assuming the policy command mirrors the repo command's sub-actions (list/add/remove); typoing `add-source`; using an older/newer Composer version whose supported actions differ; scripting against an action that was renamed.

Related errors


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