Pular para o conteúdo
ecdsa.com
Python urllib.requestPython (cryptography)

Mensagem de erro

<urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate

Também aparece como

  • urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate

O texto entre os sinais angulares é o erro do ssl subjacente e varia (“self-signed certificate in certificate chain”, “certificate has expired”, …). O Python o fecha com uma localização no código-fonte e “>”, por exemplo, “(_ssl.c:1082)>”.

Python urllib.request — urllib.error.URLError wrapping ssl.SSLCertVerificationError

O que significa

O urllib.request.urlopen() encapsula qualquer problema de conexão em URLError, por isso a falha de TLS aparece dentro de “<urlopen error …>”. Quando isso acontece com todos os sites públicos, inclusive www.python.org, o processo Python não tem nenhum certificado de CA utilizável: o caso clássico é o instalador do python.org no macOS, cujo OpenSSL embutido não lê o chaveiro do macOS (Keychain) enquanto “Install Certificates.command” não for executado.

Por que acontece

Como corrigir

  1. 1.

    macOS: executar Install Certificates.command

    Execute o script pelo Finder ou pelo terminal para cada versão do Python do python.org e depois confirme que o caminho padrão do arquivo de CAs existe.

    bash
    # macOS, python.org installer (one script per installed version)
    "/Applications/Python 3.14/Install Certificates.command"
    python3 -c "import ssl; print(ssl.get_default_verify_paths().openssl_cafile)"
  2. 2.

    Passar um contexto criado a partir do certifi

    Em scripts que precisam funcionar em qualquer lugar, crie o contexto SSL explicitamente a partir de certifi.where(); mantenha o certifi atualizado para que as raízes dele continuem em dia.

    python
    # Explicit, portable: use certifi's Mozilla bundle for this request
    # pip install certifi
    import certifi, ssl, urllib.request
    
    ctx = ssl.create_default_context(cafile=certifi.where())
    urllib.request.urlopen("https://www.python.org/", context=ctx)
  3. 3.

    Ou usar o trust store do sistema operacional

    truststore.inject_into_ssl() faz o urllib, o http.client e as bibliotecas construídas sobre o ssl verificarem pelo sistema operacional, inclusive com as raízes da empresa implantadas pela TI.

    python
    # Or verify with the operating system's store (macOS Keychain, Windows, Linux bundle)
    # pip install truststore==0.10.5
    import truststore
    truststore.inject_into_ssl()
  4. 4.

    Procurar substituições definidas no ambiente

    Remova a definição de SSL_CERT_FILE e SSL_CERT_DIR se essas variáveis apontarem para arquivos que não contêm as raízes necessárias.

    bash
    env | grep -E '^SSL_CERT_(FILE|DIR)='
    python3 -c "import ssl; print(ssl.get_default_verify_paths())"

Erros relacionados

Ver toda a base de erros de assinatura