Command-line tools

Composer "SSL operation failed with code 1": how to fix it

By · Last verified

Error messageSSL operation failed with code 1. OpenSSL Error messages: error:0A000086:SSL routines::certificate verify failed

Composer's SSL operation failed with code 1 ... certificate verify failed means PHP connected to Packagist (or your private repository) but could not verify its certificate. Usually PHP has no usable CA bundle configured, an antivirus or proxy is intercepting HTTPS, or a private repository uses a CA that PHP does not trust.

Quick fix

A missing or outdated CA file in the composer diagnose output is the usual cause.

Let Composer show you what it checks:

composer diagnose -vvv
php -r 'print_r(openssl_get_cert_locations());'
php --ini

If the CA file Composer reports is missing or outdated, set a valid bundle in the php.ini used by the CLI:

openssl.cafile = "/etc/ssl/certs/ca-certificates.crt"
curl.cainfo = "/etc/ssl/certs/ca-certificates.crt"

On Windows, download cacert.pem from curl.se, save it next to PHP, and use that path. Run composer diagnose again; the HTTPS checks should now pass.

Causes

1. PHP has no usable CA bundle

Windows PHP builds, XAMPP and custom builds often have empty openssl.cafile and curl.cainfo settings and no default CA file.

  • Confirm: openssl_get_cert_locations() points to a path that does not exist.
  • Fix: set both directives in the CLI php.ini (php --ini shows which one). Composer runs on the CLI, so the web server's php.ini does not matter here.

2. Antivirus or proxy HTTPS scanning

The Composer troubleshooting guide names Avast's HTTPS scanning on Windows as one example (see antivirus HTTPS scanning); corporate TLS-inspecting proxies behave the same way.

  • Confirm: composer diagnose finds a valid CA file but still fails, and the error disappears when HTTPS scanning is turned off or on another network.
  • Fix: exclude PHP or Composer from HTTPS scanning, or add the proxy's root to the bundle you point PHP at. Report the issue to the security vendor.

3. Outdated CA bundle or old Composer

An old cacert.pem, an unpatched OS or an old Composer release may lack current roots.

  • Fix: update the OS ca-certificates package, download a fresh cacert.pem, and run composer self-update (with a working CA setup).

4. A private repository with an internal CA

Satis, GitLab, Nexus or Artifactory repositories often use internal certificates.

  • Confirm: the failing URL is your internal host, while packagist.org works.
  • Fix: add the internal root to the bundle, or set it for Composer only:
composer config --global cafile /etc/ssl/certs/company-bundle.pem

If the server is missing its intermediate certificate, fix it on the server; check it with the SSL checker.

5. A wrong system clock

A clock far in the past or future makes valid certificates look expired. Enable time synchronisation.

Fixes by environment

Every fix points PHP at a current CA bundle that also holds any private or proxy roots; the same bundle fixes curl error 60 in other tools.

Debian / Ubuntu: sudo apt-get install --reinstall ca-certificates, then make sure /etc/php/<version>/cli/php.ini does not point to a stale custom bundle.

RHEL family: use /etc/pki/tls/certs/ca-bundle.crt; add private roots with update-ca-trust.

Windows / XAMPP / Laragon: set openssl.cafile and curl.cainfo to a downloaded cacert.pem in the php.ini that php --ini reports, and make sure extension=openssl is enabled.

Docker: install ca-certificates in the image and copy private roots in before composer install. In CI, run composer diagnose as a first step when installs fail.

Same problem in your application code: see PHP cURL error 60.

Don't do this

  • composer config -g disable-tls true. Composer's documentation calls this a security risk; every download falls back to plain HTTP.
  • composer config -g secure-http false to use an http:// mirror. It allows unauthenticated downloads of code you will execute.
  • Turning off verify_peer in a custom stream context or in Composer plugins. It disables the check that protects you from tampered packages.
  • Downloading cacert.pem from an unofficial source. Use the file from curl.se or your OS package.

FAQ

What is the difference between "SSL operation failed" and "curl error 60" in Composer?

They are the same problem seen through two PHP transports. Composer uses the curl extension when it is available and reports curl error 60; without it, PHP stream wrappers report SSL operation failed with code 1. Both mean the certificate chain could not be verified, so set both openssl.cafile and curl.cainfo.

How do I see which CA file Composer is using?

Run composer diagnose -vvv. Near the top of the output, the Checked CA file ... or Checked directory ... lines show where Composer looked for a CA bundle. If that file is missing or old, replace it with a fresh cacert.pem from curl.se or fix the php.ini setting.

Can I set the CA file only for Composer?

Yes. composer config --global cafile /path/to/ca-bundle.pem stores it in Composer's global config. The Composer docs note that on PHP 5.6 and later it is better to set openssl.cafile in php.ini, so all PHP code benefits.

Is `composer config -g disable-tls true` ever acceptable?

No for any real project. The Composer docs say it makes Composer try every HTTPS URL over HTTP with no network-level encryption, and call it a security risk. Packages are code you run; downloading them unencrypted lets anyone on the path change them.

Sources

  1. Composer: Troubleshooting
  2. Composer: Config (cafile, capath, disable-tls, secure-http)
  3. PHP manual: OpenSSL runtime configuration (openssl.cafile)
  4. PHP manual: cURL runtime configuration (curl.cainfo)
  5. curl: CA certificates extracted from Mozilla