DenverCoder1/github-readme-streak-stats · error · AssertionError
500
500
Error message
You don't have a valid SSL Certificate installed or XAMPP.
What it means
executeContributionGraphRequests() performs cURL requests to the GitHub GraphQL API. cURL error 60 (SSL certificate problem) is caught specifically and rethrown as AssertionError telling the developer their environment lacks a valid SSL CA certificate setup, commonly an XAMPP/local-dev issue.
Solutions
- Download cacert.pem and set curl.cainfo and openssl.cafile in php.ini to its path
- Update the operating system's CA certificate bundle (e.g. apt-get install --reinstall ca-certificates)
- Restart the web server/PHP-FPM after changing php.ini
- Check for TLS-intercepting proxies and add their root CA to the bundle
Example fix
// before (php.ini) ;curl.cainfo = // after curl.cainfo = "C:\xampp\php\extras\ssl\cacert.pem" openssl.cafile = "C:\xampp\php\extras\ssl\cacert.pem"
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check: can PHP reach GitHub over TLS?
$r = curl_init("https://api.github.com"); curl_setopt($r, CURLOPT_NOBODY, true); curl_setopt($r, CURLOPT_RETURNTRANSFER, true); curl_exec($r); if (curl_errno($r) === 60) { die("Fix CA bundle in php.ini"); } Try / catch
try { $graphs = getContributionGraphs($user); } catch (AssertionError $e) { if (str_contains($e->getMessage(), "SSL Certificate")) { log_ssl_config_error(); } throw $e; } Prevention
- Set curl.cainfo/openssl.cafile in php.ini on every environment
- Keep OS CA certificates updated
- Test TLS connectivity in CI/health checks
When it happens
Trigger: A cURL request to the GitHub API fails with error code 60 (CURLE_PEER_FAILED_VERIFICATION): missing or outdated CA bundle, self-signed proxies, or XAMPP's default certificate configuration.
Common situations: Local development with XAMPP where php.ini has no curl.cainfo set; corporate proxy with TLS interception; outdated CA certificate bundle on the server.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
AI-assisted analysis of DenverCoder1/github-readme-streak-stats@70dd50f921 (2026-09-15).
Data as JSON: /api/errors/bc6984b1bfe8f9a0.
Report an issue: GitHub.
Appendix: source
Thrown at src/stats.php:74
curl_multi_add_handle($multi, $handle);
}
// execute queries
$running = null;
do {
curl_multi_exec($multi, $running);
} while ($running);
// collect responses
$responses = [];
foreach ($requests as $year => $handle) {
$contents = curl_multi_getcontent($handle);
$decoded = is_string($contents) ? json_decode($contents) : null;
// if response is empty or invalid, retry request one time or throw an error
if (empty($decoded) || empty($decoded->data) || !empty($decoded->errors)) {
$message = $decoded->errors[0]->message ?? ($decoded->message ?? "An API error occurred.");
$error_type = $decoded->errors[0]->type ?? "";
// Missing SSL certificate
if (curl_errno($handle) === 60) {
throw new AssertionError("You don't have a valid SSL Certificate installed or XAMPP.", 500);
}
// Other cURL error
elseif (curl_errno($handle)) {
throw new AssertionError("cURL error: " . curl_error($handle), 500);
}
// GitHub API error - Not Found
elseif ($error_type === "NOT_FOUND") {
throw new InvalidArgumentException("Could not find a user with that name.", 404);
}
// if rate limit is exceeded, don't retry with same token
if (str_contains($message, "rate limit exceeded")) {
removeGitHubToken($tokens[$year]);
}
error_log("First attempt to decode response for $user's $year contributions failed. $message");
error_log("Contents: $contents");
// retry request
$query = buildContributionGraphQuery($user, $year);
$token = getGitHubToken();View on GitHub (pinned to 70dd50f921)