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
O Python do python.org no macOS sem os próprios certificados
comumO instalador traz um OpenSSL com o trust store vazio e um script auxiliar, “Install Certificates.command”, que instala o certifi e o vincula. Pular esse script (ou instalar depois uma nova versão secundária) deixa o urlopen sem conseguir verificar nada.
Uma imagem mínima ou um build personalizado do Python sem bundle de CAs
ocasionalUm Python compilado a partir do código-fonte ou copiado para uma imagem scratch ou distroless procura o caminho padrão do bundle do OpenSSL, que não existe ali.
Um proxy com inspeção de TLS
ocasionalSe só alguns sites falham, ou se as falhas começaram em uma rede corporativa, a causa provável é uma raiz de proxy em que este Python não confia.
SSL_CERT_FILE ou SSL_CERT_DIR aponta para o lugar errado
raraEssas variáveis substituem os locais padrão para o processo inteiro; um arquivo vazio ou sem relação com o caso quebra todas as verificações.
Como corrigir
- 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.
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.
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.
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())"