symfony/translation · error · InvalidArgumentException

The translation provider DSN must contain a scheme.

Error message

The translation provider DSN must contain a scheme.

What it means

After parse_url succeeds, Dsn requires a scheme component. A DSN like '://host' or '//host' (protocol-relative) has no scheme, so the factory cannot know which translation provider to instantiate; InvalidArgumentException is thrown.

Solutions

  1. Prefix the DSN with its scheme, e.g. 'loco://...'.
  2. Check that config interpolation didn't consume the '//' separator.
  3. Use the exact scheme supported by the factory (see getSupportedSchemes of the intended provider).
  4. Validate the DSN starts with a scheme followed by '://' before constructing.

Example fix

// before
new Dsn('//api.locoapp');

// after
new Dsn('loco://api.locoapp');
Defensive patterns

Strategy: validation

Validate before calling

if (!str_contains($dsn, '://')) {
    throw new \InvalidArgumentException('DSN must include a scheme, e.g. loco://...');
}

Try / catch

try {
    $dsn = new Dsn($rawDsn);
} catch (\InvalidArgumentException $e) {
    // prepend the correct scheme or fix the config value
}

Prevention

When it happens

Trigger: new Dsn('//host') or a scheme-less DSN string reaching any translation provider factory; env var set to a host-only value; template/config dropping the 'scheme://' prefix.

Common situations: Config values like 'loco-host' without 'loco://', stripping the scheme while joining URL parts, or defaults written as '//default'.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of symfony/translation@ae9e8a51bc (2026-09-15). Data as JSON: /api/errors/4e1a678370341cc4. Report an issue: GitHub.

Appendix: source

Thrown at Provider/Dsn.php:41

    private ?string $scheme;
    private ?string $host;
    private ?string $user;
    private ?string $password;
    private ?int $port;
    private ?string $path;
    private array $options = [];
    private string $originalDsn;

    public function __construct(#[\SensitiveParameter] string $dsn)
    {
        $this->originalDsn = $dsn;

        if (false === $params = parse_url($dsn)) {
            throw new InvalidArgumentException('The translation provider DSN is invalid.');
        }

        if (!isset($params['scheme'])) {
            throw new InvalidArgumentException('The translation provider DSN must contain a scheme.');
        }
        $this->scheme = $params['scheme'];

        if (!isset($params['host'])) {
            throw new InvalidArgumentException('The translation provider DSN must contain a host (use "default" by default).');
        }
        $this->host = $params['host'];

        $this->user = '' !== ($params['user'] ?? '') ? rawurldecode($params['user']) : null;
        $this->password = '' !== ($params['pass'] ?? '') ? rawurldecode($params['pass']) : null;
        $this->port = $params['port'] ?? null;
        $this->path = $params['path'] ?? null;
        parse_str($params['query'] ?? '', $this->options);
    }

    public function getScheme(): string
    {
        return $this->scheme;

View on GitHub (pinned to ae9e8a51bc)