{"record":{"id":"519c1c7b14c6b628","repo":"symfony/translation","slug":"the-translation-provider-dsn-is-invalid","errorCode":null,"errorMessage":"The translation provider DSN is invalid.","messagePattern":"The translation provider DSN is invalid\\.","errorType":"exception","errorClass":"InvalidArgumentException","httpStatus":null,"severity":"error","filePath":"Provider/Dsn.php","lineNumber":37,"sourceCode":" * @author Oskar Stark <oskarstark@googlemail.com>\n */\nfinal class Dsn\n{\n    private ?string $scheme;\n    private ?string $host;\n    private ?string $user;\n    private ?string $password;\n    private ?int $port;\n    private ?string $path;\n    private array $options = [];\n    private string $originalDsn;\n\n    public function __construct(#[\\SensitiveParameter] string $dsn)\n    {\n        $this->originalDsn = $dsn;\n\n        if (false === $params = parse_url($dsn)) {\n            throw new InvalidArgumentException('The translation provider DSN is invalid.');\n        }\n\n        if (!isset($params['scheme'])) {\n            throw new InvalidArgumentException('The translation provider DSN must contain a scheme.');\n        }\n        $this->scheme = $params['scheme'];\n\n        if (!isset($params['host'])) {\n            throw new InvalidArgumentException('The translation provider DSN must contain a host (use \"default\" by default).');\n        }\n        $this->host = $params['host'];\n\n        $this->user = '' !== ($params['user'] ?? '') ? rawurldecode($params['user']) : null;\n        $this->password = '' !== ($params['pass'] ?? '') ? rawurldecode($params['pass']) : null;\n        $this->port = $params['port'] ?? null;\n        $this->path = $params['path'] ?? null;\n        parse_str($params['query'] ?? '', $this->options);\n    }","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/symfony/translation/blob/ae9e8a51bc29780d63c7f9efd6005d7c875e100b/Provider/Dsn.php#L19-L55","documentation":"Translation provider Dsn::__construct parses the DSN string with parse_url. If parse_url fails (the string is not a well-formed URL), an InvalidArgumentException is thrown because the rest of Dsn cannot be built. This is the first validity gate for every translation provider DSN.","triggerScenarios":"Passing a malformed DSN such as 'loco://' + unencoded special characters (spaces, bare '%', broken brackets) or a completely non-URL string like 'my translation key' to new Dsn(...) or a provider factory.","commonSituations":"Secrets containing special characters like @, :, /, or % not rawurlencoded; missing scheme separator typos ('loco://host:' with trailing garbage); shell interpolation producing empty/garbled DSNs in env vars.","solutions":["Fix the DSN syntax so it is a valid URL: scheme://user:pass@host:port/path.","rawurlencode the user and password (especially secrets with @ : / % ? # characters).","Print the DSN source (env var, config) and check for trimming/interpolation issues — never log the secret itself.","Test with `var_dump(parse_url($dsn))` to see exactly what parse_url rejects."],"exampleFix":"// before\nnew Dsn('loco://' . $key); // $key = 'a b@c%' -> parse_url fails\n\n// after\nnew Dsn('loco://' . rawurlencode($key) . '@api.locoapp');","handlingStrategy":"try-catch","validationCode":"if (false === parse_url($dsn)) {\n    throw new \\InvalidArgumentException('Malformed translation provider DSN');\n}","typeGuard":null,"tryCatchPattern":"try {\n    $dsn = new Dsn($rawDsn);\n} catch (\\InvalidArgumentException $e) {\n    // log a redacted version of $rawDsn and fix quoting/encoding\n}","preventionTips":["rawurlencode user and password parts of every DSN.","Avoid shell/env interpolation that can inject spaces or empty strings.","Smoke-test provider DSN construction in CI with representative values."],"tags":["dsn","url-parsing","translation-provider","invalid-url"],"backgroundTag":"invalid-url-format","analyzedSha":"ae9e8a51bc29780d63c7f9efd6005d7c875e100b","analyzedAt":"2026-09-15T22:29:15.305Z","contentChangedAt":"2026-09-15T22:29:15.305Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}