# Fix curl: (3) URL using bad/illegal format

Why curl stops with error 3, URL using bad/illegal format or missing URL, and how to fix each cause in bash, zsh, cmd and PowerShell.

`curl: (3) URL using bad/illegal format or missing URL` means curl could not read the address you gave it as a URL. Almost always the shell or a copy-paste changed it on the way: a space, a smart quote, an unescaped `&`, a stray line break. Put the whole URL in double quotes, encode spaces as `%20`, and pass a URL that sits inside another URL with `--data-urlencode`:

```bash
curl -G "https://curlshot.com/api/v1/screenshot" \
  -H "X-Access-Key: YOUR_ACCESS_KEY" \
  --data-urlencode "url=https://shop.example/item?id=7&color=red" \
  -d "format=png" \
  --output item.png
```

curl encodes the page address for you, so the API receives one `url` option with `id=7&color=red` kept inside it, and you get `item.png`.

Recent curl versions name the reason after `URL rejected:`. Older versions, and many programs built on libcurl, print only the general text for error 3, `URL using bad/illegal format or missing URL`. It is the same error, and the same fixes apply.

| curl says | Usual cause | Fix |
| --- | --- | --- |
| `URL rejected: Malformed input to a URL function` | A space, a tab or a line-break character in the URL | [Step 1](#1-remove-spaces-tabs-and-line-breaks) |
| `URL rejected: Port number was not a decimal number between 0 and 65535` | Smart quotes, or single quotes in Windows `cmd`, became part of the URL | [Step 4](#4-replace-smart-quotes-and-hidden-characters), [step 6](#6-use-double-quotes-on-windows) |
| `URL rejected: Bad hostname` | A `\` line break in Windows `cmd` or PowerShell was passed to curl as a URL | [Step 5](#5-check-how-a-long-command-is-split-over-lines) |
| `unmatched brace in URL position N` or `bad range in URL position N` | `{ }` or `[ ]` in the URL, which curl reads as a pattern | [Step 7](#7-turn-off-globbing-for-braces-and-brackets) |
| `URL rejected: No host part in the URL` | The URL has no host, e.g. `https://` alone or an empty variable before the path | [Step 8](#8-check-the-scheme-and-the-host) |

Every command on this page was run with curl 8.7 in bash, zsh and PowerShell 7.

## 1. Remove spaces, tabs and line breaks

A URL cannot contain a space, even inside quotes. curl refuses it:

```bash
curl "https://example.com/my page"
# curl: (3) URL rejected: Malformed input to a URL function
```

Write the space as `%20`:

```bash
curl "https://example.com/my%20page"
```

A tab, or a carriage return (`\r`) at the end of a line read from a file saved on Windows, fails in the same way. Remove the `\r` before you use the value:

```bash
curl "$(tr -d '\r' < url.txt)"
```

## 2. Put the URL in double quotes

`&`, `?`, `*` and `#` mean something to the shell. Without quotes, the shell acts on them before curl starts:

```bash
curl https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com
```

- In **bash**, `&` sends the command to the background and cuts the URL there. curl only gets `...?access_key=YOUR_ACCESS_KEY`, and the shell reads `url=https://example.com` as a separate command, so the page address is lost.
- In **zsh**, `?` is a wildcard, so the command stops before curl runs with `zsh: no matches found`.

Quote the whole URL, from the first character to the last:

```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://example.com" \
  --output example.png
```

## 3. Encode a URL that sits inside another URL

A screenshot API takes the page to capture as a parameter, so one URL travels inside another. If the inner URL has its own `?`, `&` or `#`, those characters split the outer one:

```bash
curl "https://curlshot.com/api/v1/screenshot?access_key=YOUR_ACCESS_KEY&url=https://shop.example/item?id=7&color=red"
```

curl does not complain here, but the API receives `url=https://shop.example/item?id=7` and a separate `color=red`. CurlShot refuses the unknown `color` option with [`invalid_options`](https://curlshot.com/docs/errors.md#invalid_options). A `#` is worse: it ends the URL, and everything after it is never sent.

Let curl encode the inner URL. `-G` puts the data in the query string of a GET request, and `--data-urlencode` encodes the value after `url=`:

```bash
curl -G "https://curlshot.com/api/v1/screenshot" \
  -H "X-Access-Key: YOUR_ACCESS_KEY" \
  --data-urlencode "url=https://example.com/docs?lang=en#install" \
  -d "full_page=true" \
  --output docs.png
```

The API receives `url=https%3a%2f%2fexample.com%2fdocs%3flang%3den%23install`, which it decodes back to the full address. The same pattern is used in the [cURL examples](https://curlshot.com/docs/examples/curl.md#add-options).

## 4. Replace smart quotes and hidden characters

Chat apps, word processors and some web pages turn `"` into curly quotes, `“` and `”`. The shell does not treat them as quotes, so they become part of the URL:

```bash
curl “https://example.com”
# curl: (3) URL rejected: Port number was not a decimal number between 0 and 65535
```

Retype the quotes as plain `"`. To see characters you cannot see on screen, print the value with `printf %q`. This is the output in bash; zsh shows the same characters in a slightly different form:

```bash
printf '%q\n' "$URL"
# $'\342\200\234https://example.com\342\200\235'   <- smart quotes
# $'https://example.com/a\r'                     <- a carriage return
```

## 5. Check how a long command is split over lines

Each shell has its own line-continuation character, and it must be the very last character on the line:

| Shell | Continue a line with |
| --- | --- |
| bash, zsh | `\` |
| Windows `cmd` | `^` |
| PowerShell | `` ` `` (backtick) |

A space after `\` in bash or zsh breaks the command in two, and curl gets a lone space as a URL: `URL rejected: Malformed input to a URL function`. A `\` used in `cmd` or PowerShell is passed to curl as a URL of its own: `URL rejected: Bad hostname`.

This is the request from the top of the page in PowerShell:

```text
curl.exe -G "https://curlshot.com/api/v1/screenshot" `
  -H "X-Access-Key: YOUR_ACCESS_KEY" `
  --data-urlencode "url=https://shop.example/item?id=7&color=red" `
  -d "format=png" `
  --output item.png
```

And in `cmd`:

```text
curl -G "https://curlshot.com/api/v1/screenshot" ^
  -H "X-Access-Key: YOUR_ACCESS_KEY" ^
  --data-urlencode "url=https://shop.example/item?id=7&color=red" ^
  -d "format=png" ^
  --output item.png
```

When in doubt, put the whole command on one line.

## 6. Use double quotes on Windows

`cmd` only knows double quotes. Single quotes are passed on to curl as part of the URL, which then starts with `'https`:

```text
curl 'https://example.com'
```

```text
curl "https://example.com"
```

In `cmd`, `&` outside double quotes also starts a new command. In a `.bat` file, write each `%` of an encoded URL twice (`%%20`), or `cmd` reads it as a variable.

In Windows PowerShell 5.1, `curl` is an alias of `Invoke-WebRequest`, not curl, so curl options fail with a PowerShell error. Type `curl.exe` instead. PowerShell 7 and later have no such alias. In PowerShell, single and double quotes both work, and `&` outside quotes is an error or a background job, so quote the URL there too.

## 7. Turn off globbing for braces and brackets

curl reads `{a,b}` and `[1-5]` in a URL as patterns and fetches every match. An unclosed or unexpected one stops it:

```bash
curl "https://example.com/search?filter={a"
# curl: (3) unmatched brace in URL position 35:
```

Add `-g` (`--globoff`) to send the characters as they are:

```bash
curl -g "https://example.com/search?filter={a"
```

Or encode them: `{` is `%7B`, `}` is `%7D`, `[` is `%5B` and `]` is `%5D`. With `--data-urlencode`, as in [step 3](#3-encode-a-url-that-sits-inside-another-url), the brackets are encoded for you.

## 8. Check the scheme and the host

A URL with a scheme but no host fails:

```bash
curl "https://"
# curl: (3) URL rejected: No host part in the URL
```

This often comes from a variable that is empty, for example `curl "https://$HOST/path"` when `$HOST` was never set. Print the variable before the call. When the whole URL is an empty variable, `curl "$URL"`, recent curl versions stop with `option : blank argument where content is expected` instead.

curl itself accepts `example.com` without `https://` and guesses the scheme. The `url` option of the CurlShot API does not: it needs a full address that starts with `http://` or `https://`, or the request fails with [`invalid_options`](https://curlshot.com/docs/errors.md#invalid_options).

## Questions

### What does curl error 3 mean?

Error 3 is `CURLE_URL_MALFORMAT`: the URL was not properly formatted, so curl stopped before it connected to anything. Nothing was sent, so a server or an API cannot be the cause.

### Why does the URL work in my browser but not in curl?

The browser fixes the address for you: it encodes spaces and other characters before it sends the request. curl sends the URL exactly as it gets it, and the shell may have changed it before curl even started.

### Should I use single or double quotes?

In bash, zsh and PowerShell, either works. Single quotes stop the shell from expanding `$VARIABLES`, double quotes allow it. In Windows `cmd`, use double quotes only.

### How do I pass a URL with `&` as a query parameter?

Use `-G` with `--data-urlencode "url=..."`, as in [step 3](#3-encode-a-url-that-sits-inside-another-url). curl encodes the `&`, `?` and `#` of the inner URL, so the server receives it as one value.

### Does `-g` change my request?

Only how curl reads the URL you typed: `{ }` and `[ ]` are sent as they are instead of being expanded into several requests. Use it whenever a URL has those characters and you want one request.

## Next steps

- Copy a working request from the [cURL examples](https://curlshot.com/docs/examples/curl.md).
- Get an access key and take a first screenshot in [Getting started](https://curlshot.com/docs/getting-started.md).
- If the request reaches the API and fails there, the answer is a JSON message. [Errors](https://curlshot.com/docs/errors.md) lists every code with its fix.
- No account yet? [Create one for free](https://curlshot.com/register).
