{"record":{"id":"fcf30a007ee278f2","repo":"kubernetes/kops","slug":"fetching-intermediate-certificate-from-s-status","errorCode":null,"errorMessage":"fetching intermediate certificate from %s: status %d","messagePattern":"fetching intermediate certificate from (.+?): status (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/azure/attest.go","lineNumber":437,"sourceCode":"\t\t\t// Fetched, but nothing matched current's issuer; stop with what we have.\n\t\t\tbreak\n\t\t}\n\t\tcurrent = issuer\n\t}\n\n\treturn pool, nil\n}\n\n// fetchCertificate fetches and parses a DER-encoded certificate from the given URL.\nfunc fetchCertificate(client *http.Client, url string) (*x509.Certificate, error) {\n\tresp, err := client.Get(url)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"fetching intermediate certificate from %s: %w\", url, err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"fetching intermediate certificate from %s: status %d\", url, resp.StatusCode)\n\t}\n\n\t// Cap the body read to reject pathologically large responses. Read one extra byte so we can\n\t// distinguish \"at the limit\" from \"exceeded limit\".\n\tbody, err := io.ReadAll(io.LimitReader(resp.Body, intermediateCertMaxResponseBytes+1))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading intermediate certificate from %s: %w\", url, err)\n\t}\n\tif len(body) > intermediateCertMaxResponseBytes {\n\t\treturn nil, fmt.Errorf(\"intermediate certificate from %s exceeds %d bytes\", url, intermediateCertMaxResponseBytes)\n\t}\n\n\tcert, err := x509.ParseCertificate(body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"parsing intermediate certificate from %s: %w\", url, err)\n\t}\n\treturn cert, nil\n}","sourceCodeStart":419,"sourceCodeEnd":455,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/azure/attest.go#L419-L455","documentation":"fetchCertificate requires the AIA endpoint to answer with HTTP 200. Any other status (404 for a retired intermediate, 403 for blocked access, 5xx for CA outages) is converted to this error, which embeds the URL and the offending status code for diagnostics.","triggerScenarios":"fetchCertificate receives a response with StatusCode != http.StatusOK while fetching an intermediate certificate from an AIA URL.","commonSituations":"Intermediate certificate retired/rotated so its URL 404s; corporate proxy returning 403; CA endpoint outage returning 503; CDN misconfiguration.","solutions":["Check the URL with curl -I to see the actual status and confirm the certificate URL is still valid","Re-read the current signer's AIA extension — the URL may have been rotated by the CA","Retry after transient 5xx; the negative cache will throttle repeated attempts","Clear any proxy that injects non-200 responses for the CA host"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"resp, err := http.Head(url)\nif err != nil || resp.StatusCode != http.StatusOK {\n    return nil, fmt.Errorf(\"AIA URL %s unhealthy (status %v)\", url, resp.StatusCode)\n}\nresp.Body.Close()","typeGuard":null,"tryCatchPattern":"_, err := fetchCertificate(client, url)\nvar statusErr interface{ } \nif err != nil && strings.Contains(err.Error(), \"status \") {\n    code := extractStatusCode(err.Error())\n    if code >= 500 { /* retry with backoff */ } else { /* fail fast: URL retired or forbidden */ }\n}","preventionTips":["Monitor CA endpoint availability and rotation notices","Re-read AIA URLs from current signer certificates instead of hardcoding them","Retry only 5xx; treat 4xx as a permanent configuration problem"],"tags":["http","azure","tls","aia-fetch","http-status"],"backgroundTag":"http-non-200-response","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}