Skip to the content.

curl Malformed URL Errors in C# (CurlMalformedUrlException)

curl URL errors in C# fall into three cases, each with its own exception in CurlDotNet: a URL that cannot be parsed throws CurlMalformedUrlException (curl error code 3), a scheme CurlDotNet does not handle throws CurlUnsupportedProtocolException (code 1), and a command with no URL at all throws CurlInvalidCommandException. Mistakes in the options themselves (a missing value, two request methods, a line break in a header) throw before anything is sent, with the exit code curl uses. This page shows what triggers each one and how to validate a command before running it.

The Three Exceptions

using CurlDotNet;
using CurlDotNet.Exceptions;

try
{
    var result = await Curl.ExecuteAsync("curl htp://example.com/path");
}
catch (CurlMalformedUrlException ex)      { Console.WriteLine($"Bad URL: {ex.Message}"); }
catch (CurlUnsupportedProtocolException ex) { Console.WriteLine(ex.Message); }   // htp:// is not a scheme CurlDotNet handles
catch (CurlInvalidCommandException ex)    { Console.WriteLine($"Bad command near '{ex.InvalidPart}'"); }
Input Exception Why
curl "https://exa mple.com" CurlMalformedUrlException (3) Space inside the host name
curl https://example.com:abc CurlMalformedUrlException (3) Port is not a number
curl gopher://example.com CurlUnsupportedProtocolException (1) Scheme has no handler
curl htp://example.com CurlUnsupportedProtocolException (1) Typo in the scheme
curl -X GET CurlInvalidCommandException (2) Options but no URL (InvalidPart is "URL")
curl CurlException (2) Nothing after the program name
curl 'https://example.com/[1-' CurlException (3) Malformed URL glob

Like command-line curl, CurlDotNet prepends http:// to a URL without a scheme (ftp:// when the host starts with ftp.), so curl example.com works. Write https:// explicitly when you want TLS. CurlMalformedUrlException is also thrown when a redirect’s Location header is not a valid URL, and CurlUnsupportedProtocolException when a -L redirect points at a scheme other than http or https.

Command and Option Errors

These are thrown while the command is parsed, before any network activity:

Problem Exception CurlErrorCode
An option is the last word and has no value (curl https://example.com -H) CurlException 2
Two request methods: -I with -d, -F with -d, --json with -F… CurlException 2
A numeric option with a value that is not a number (-m abc, --retry x, --max-redirs, --connect-timeout, --retry-delay, --retry-max-time, --speed-limit, --speed-time, --limit-rate, --max-filesize); the message names the option. Seconds are read like curl, so -m 1e1 and -m +5 are accepted CurlException 2
--aws-sigv4 malformed (empty, white space, more than four : parts); AwsSigV4Config.Parse throws the same CurlInvalidCommandException 2
-C with --no-clobber, -K files nested too deep, --variable errors CurlException 2
-H @file where the file does not exist CurlReadErrorException 26
-o uses #<name> for a glob the URL does not name CurlException 43
CR or LF inside a -H value or --request-target, space in --request-target CurlBadFunctionArgumentException (property ArgumentName) 43
-C/--continue-at with a request body (-d, -F, -T) CurlBadFunctionArgumentException 43
--resolve / --connect-to entry with a non-numeric port CurlOptionSyntaxException (a CurlInvalidCommandException) 49
Options but no URL CurlInvalidCommandException 2
using CurlDotNet;
using CurlDotNet.Exceptions;

try
{
    await Curl.ExecuteAsync("curl -I -d 'a=1' https://httpbin.org/post");
}
catch (CurlException ex) when (ex.CurlErrorCode == 2)
{
    Console.WriteLine(ex.Message);   // You can only select one HTTP request method, ...
}

A header with a line break is refused because the rest of the line would be sent as extra headers or a second request:

try
{
    var userInput = "abc\r\nX-Admin: true";
    await Curl.ExecuteAsync($"curl -H 'X-Token: {userInput}' https://httpbin.org/headers");
}
catch (CurlBadFunctionArgumentException ex)
{
    Console.WriteLine($"{ex.ArgumentName}: {ex.Message}");   // -H/--header: The value given with -H/--header contains a line break ...
}

Unknown options (typos such as --hedaer) do not throw: the command runs and the typo is listed in CurlOptions.UnknownOptions. Curl.Validate reports it, so validate commands that come from users or configuration. CurlUnknownOptionException, CurlNotSupportedException (code 1) and CurlNotBuiltInException (code 4) exist in CurlDotNet.Exceptions but nothing throws them today.

Validating Before Executing

Curl.Validate parses the command without sending anything, and reports a missing URL, unknown options and unsupported schemes:

var check = Curl.Validate("curl -X POST https://httpbin.org/post -d 'a=1'");

if (!check.IsValid)
    Console.WriteLine($"Invalid command: {check.Error}");

For a URL on its own, .NET’s Uri.TryCreate tells you whether it is absolute and which scheme it uses:

bool IsHttpUrl(string url) =>
    Uri.TryCreate(url, UriKind.Absolute, out var uri)
    && (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps);

Common Mistakes

Missing Scheme

// Works, but over plain HTTP: curl (and CurlDotNet) prepend http://
var r1 = await Curl.ExecuteAsync("curl httpbin.org/get");

// Say https:// when you want TLS
var r2 = await Curl.ExecuteAsync("curl https://httpbin.org/get");

Unencoded Characters

Spaces and most punctuation must be percent-encoded in the path and query:

var fileName = "my report.pdf";
var url = $"https://httpbin.org/anything/{Uri.EscapeDataString(fileName)}";   // my%20report.pdf
var result = await Curl.ExecuteAsync($"curl {url}");

Query Strings Built by Hand

Encode each value with Uri.EscapeDataString, or let curl do it with --data-urlencode (which, like curl, encodes spaces as +) or -G --data-urlencode for a query string:

var q = Uri.EscapeDataString("c# & .net");
var r1 = await Curl.ExecuteAsync($"curl 'https://httpbin.org/get?q={q}'");

// POST form field, encoded by curl
var r2 = await Curl.ExecuteAsync("curl --data-urlencode 'q=c# & .net' https://httpbin.org/post");

Quoting URLs with Special Characters

&, ? and spaces are safe inside the C# string, but wrap the URL in single quotes when it contains spaces or characters the command parser could split on:

var result = await Curl.ExecuteAsync("curl 'https://httpbin.org/get?a=1&b=2'");

Building URLs Safely

var builder = new UriBuilder("https", "httpbin.org")
{
    Path = "/anything/users",
    Query = $"name={Uri.EscapeDataString("Alice Smith")}&page=2"
};

var result = await Curl.ExecuteAsync($"curl '{builder.Uri}'");

Supported Schemes

CurlDotNet handles http://, https://, ftp:// and file://. Anything else (sftp://, scp://, smtp://, imap://, ldap://, telnet:// and so on) raises CurlUnsupportedProtocolException. See supported protocols.