Depuração6 min de leitura

Como Corrigir o Erro ERR_INVALID_URL no Node.js

O erro ERR_INVALID_URL no Node.js ocorre quando o construtor URL ou url.parse() recebe uma string que não é uma URL válida. As causas mais comuns incluem a ausência de protocolo, caracteres especiais não codificados e percent-encoding malformado. Corrija-o validando a entrada e codificando os caracteres especiais antes de fazer o parsing.

O Que Causa o Erro ERR_INVALID_URL?

O erro ERR_INVALID_URL (formalmente TypeError [ERR_INVALID_URL]: Invalid URL) é lançado pelo Node.js quando o construtor URL ou a função legada url.parse() recebe uma string que não pode ser interpretada como uma URL válida. Esse erro é comum ao processar entradas do usuário, ao fazer o parsing de arquivos de configuração ou ao lidar com URLs de fontes externas.

O construtor URL segue o WHATWG URL Standard, que é mais rigoroso do que o antigo parsing baseado em RFC. Para ser aceita como uma URL válida, uma string deve incluir um esquema válido (como https:), uma autoridade válida (nome de host) e componentes de caminho e query devidamente formatados.

// Isto lança ERR_INVALID_URL
try {
  const url = new URL('not-a-url');
} catch (err) {
  console.log(err.code);    // 'ERR_INVALID_URL'
  console.log(err.message); // 'Invalid URL: not-a-url'
  console.log(err.input);   // 'not-a-url'
}

Causas Comuns e Soluções

Causa 1: Protocolo/esquema ausente. O construtor URL exige um esquema como https:// ou http://. Strings como example.com/path ou www.example.com vão falhar.

// FALHA: sem protocolo
new URL('example.com/path');  // ERR_INVALID_URL

// SOLUÇÃO: adicione o protocolo
new URL('https://example.com/path');  // Funciona!

// SOLUÇÃO: adicione o protocolo caso esteja ausente
function ensureProtocol(urlString) {
  if (!/^https?:\/\//i.test(urlString)) {
    return 'https://' + urlString;
  }
  return urlString;
}
new URL(ensureProtocol('example.com/path'));  // Funciona!

Causa 2: Caracteres especiais não codificados. Caracteres como espaços, chaves, barras verticais e certos caracteres Unicode não são permitidos em URLs sem codificação.

// FALHA: espaços e caracteres especiais não codificados
new URL('https://example.com/my file.pdf');    // ERR_INVALID_URL
new URL('https://example.com/path?q=a b');     // Pode falhar em algumas versões

// SOLUÇÃO: codifique as partes problemáticas
const filename = encodeURIComponent('my file.pdf');
new URL('https://example.com/' + filename);    // Funciona!

// SOLUÇÃO: use encodeURI para uma URL completa com espaços
const rawUrl = 'https://example.com/my file.pdf';
new URL(encodeURI(rawUrl));  // Funciona!

Causa 3: Percent-encoding malformado. Se uma URL contém um sinal de porcentagem que não é seguido por exatamente dois dígitos hexadecimais, o parser a rejeita.

// FALHA: percent-encoding malformado
new URL('https://example.com/100%done');       // ERR_INVALID_URL
new URL('https://example.com/path?q=50%');     // ERR_INVALID_URL

// SOLUÇÃO: codifique o sinal de porcentagem isolado como %25
function fixPercentSigns(urlString) {
  return urlString.replace(/%(?![0-9A-Fa-f]{2})/g, '%25');
}
new URL(fixPercentSigns('https://example.com/100%done'));
// Funciona! A URL passa a ser https://example.com/100%25done

Causa 4: Entrada vazia ou nula. Passar uma string vazia, null ou undefined para o construtor URL também dispara esse erro.

// FALHA: entrada vazia ou nula
new URL('');           // ERR_INVALID_URL
new URL(null);         // ERR_INVALID_URL
new URL(undefined);    // ERR_INVALID_URL

// SOLUÇÃO: valide a entrada antes de fazer o parsing
function parseUrl(input) {
  if (!input || typeof input !== 'string') {
    return null;
  }
  try {
    return new URL(input);
  } catch {
    return null;
  }
}

Causa 5: URLs relativas sem uma base. Por padrão, o construtor URL trata o primeiro argumento como uma URL absoluta. URLs relativas como /path/to/page exigem uma URL base como segundo argumento.

// FALHA: URL relativa sem base
new URL('/api/users');  // ERR_INVALID_URL

// SOLUÇÃO: forneça uma URL base
new URL('/api/users', 'https://example.com');
// Funciona! → https://example.com/api/users

// Padrão útil para clientes de API
const BASE_URL = 'https://api.example.com';
const endpoint = new URL('/v2/users?page=1', BASE_URL);
console.log(endpoint.href);
// "https://api.example.com/v2/users?page=1"

Como Validar URLs Antes do Parsing

A maneira mais confiável de validar uma URL no Node.js é usar o construtor URL dentro de um bloco try-catch. Não existe um método URL.isValid() embutido (até o Node.js 22), portanto capturar o erro é a abordagem padrão.

// Validador simples de URL
function isValidUrl(string) {
  try {
    new URL(string);
    return true;
  } catch {
    return false;
  }
}

console.log(isValidUrl('https://example.com'));  // true
console.log(isValidUrl('not-a-url'));            // false
console.log(isValidUrl(''));                     // false

// Validador com protocolos permitidos
function isValidHttpUrl(string) {
  try {
    const url = new URL(string);
    return url.protocol === 'http:' || url.protocol === 'https:';
  } catch {
    return false;
  }
}

console.log(isValidHttpUrl('https://example.com'));     // true
console.log(isValidHttpUrl('ftp://example.com'));       // false
console.log(isValidHttpUrl('javascript:alert(1)'));     // false

Padrão de Parsing Seguro de URLs

Aqui está um padrão robusto de parsing de URLs que lida com todos os casos de erro comuns e retorna um objeto URL interpretado ou um erro significativo.

class UrlParser {
  static parse(input, base) {
    // Valida a entrada
    if (!input || typeof input !== 'string') {
      return { ok: false, error: 'Input must be a non-empty string' };
    }

    // Remove espaços em branco nas extremidades
    const trimmed = input.trim();

    // Corrige problemas comuns
    let urlString = trimmed;

    // Adiciona o protocolo caso esteja ausente
    if (/^[a-zA-Z0-9]/.test(urlString) && !urlString.includes('://')) {
      urlString = 'https://' + urlString;
    }

    // Corrige sinais de porcentagem isolados
    urlString = urlString.replace(/%(?![0-9A-Fa-f]{2})/g, '%25');

    try {
      const url = base ? new URL(urlString, base) : new URL(urlString);

      // Opcional: restringe a protocolos seguros
      if (!['http:', 'https:'].includes(url.protocol)) {
        return { ok: false, error: 'Unsupported protocol: ' + url.protocol };
      }

      return { ok: true, url };
    } catch (err) {
      return { ok: false, error: err.message };
    }
  }
}

// Uso
const result = UrlParser.parse('example.com/path?q=hello world');
if (result.ok) {
  console.log(result.url.href);
} else {
  console.error(result.error);
}

Boas Práticas de Prevenção

Seguir estas práticas vai ajudá-lo a evitar erros ERR_INVALID_URL em suas aplicações Node.js e a construir um tratamento de URLs mais resiliente.

  • Sempre envolva o parsing de URLs em try-catch. Nunca presuma que uma string de URL é válida, especialmente quando ela vem de entrada do usuário, variáveis de ambiente, bancos de dados ou APIs externas.
  • Use a API URL em vez de concatenação de strings. Construa URLs usando o construtor URL e o URLSearchParams em vez de concatenar strings. A API cuida da codificação automaticamente.
  • Valide as variáveis de ambiente na inicialização. Se a sua aplicação lê URLs de variáveis de ambiente ou arquivos de configuração, valide-as quando a aplicação é iniciada, e não quando elas são usadas pela primeira vez.
  • Codifique a entrada do usuário antes de inseri-la em URLs. Use sempre encodeURIComponent() para valores de parâmetros de query e encodeURI() para URLs completas fornecidas pelos usuários.
  • Use um construtor de URLs para casos complexos. Para montar URLs com muitas partes dinâmicas, crie uma função auxiliar ou uma classe que trate a codificação de forma consistente.
  • Registre a entrada original em caso de erro. Quando você capturar um erro ERR_INVALID_URL, registre a entrada que o causou (higienizada, caso possa conter dados sensíveis) para ajudar a depurar o problema.
// Boa prática: valide as URLs de configuração na inicialização
const requiredUrls = ['API_BASE_URL', 'AUTH_SERVER_URL', 'WEBHOOK_URL'];

for (const envVar of requiredUrls) {
  const value = process.env[envVar];
  if (!value) {
    throw new Error(envVar + ' environment variable is required');
  }
  try {
    new URL(value);
  } catch {
    throw new Error(envVar + ' is not a valid URL: ' + value);
  }
}

// Boa prática: use a API URL para construir URLs
function buildApiUrl(endpoint, params) {
  const url = new URL(endpoint, process.env.API_BASE_URL);
  for (const [key, value] of Object.entries(params)) {
    url.searchParams.set(key, String(value));
  }
  return url.toString();
}

const searchUrl = buildApiUrl('/api/search', {
  q: 'Node.js & Express',
  page: 1
});
// "https://api.example.com/api/search?q=Node.js+%26+Express&page=1"

Artigos relacionados

Experimente as nossas ferramentas gratuitas