crowdsecurity/crowdsec · error
could not parse file: %w
Error message
could not parse file: %w
What it means
decodeCRLs fails when a PEM block found in the CRL file is not a valid x509 revocation list (x509.ParseRevocationList errors). To avoid serving a truncated/corrupt CRL, the whole file is invalidated and the previous CRL version keeps being used.
Source
Thrown at pkg/apiserver/middlewares/v1/crl.go:53
return cc, nil
}
func (*CRLChecker) decodeCRLs(content []byte) ([]*x509.RevocationList, error) {
var crls []*x509.RevocationList
for {
block, rest := pem.Decode(content)
if block == nil {
break // no more PEM blocks
}
content = rest
crl, err := x509.ParseRevocationList(block.Bytes)
if err != nil {
// invalidate the whole CRL file so we can still use the previous version
return nil, fmt.Errorf("could not parse file: %w", err)
}
crls = append(crls, crl)
}
return crls, nil
}
// refresh() reads the CRL file if new or changed since the last time
func (cc *CRLChecker) refresh() error {
// noop if lastLoad is less than 5 seconds ago
if time.Since(cc.lastLoad) < 5*time.Second {
return nil
}
cc.mu.Lock()
defer cc.mu.Unlock()
View on GitHub (pinned to 909b515798)
Solutions
- Regenerate/redownload the CRL file from the CA in a valid PEM DER format (openssl ca -gencrl / openssl crl -in crl.der -out crl.pem)
- Check the file contains only PEM 'X509 CRL' blocks: openssl crl -in <file> -noout -text
- Fix the process writing the CRL so it writes atomically (write temp file + rename) instead of truncating in place
- Verify the LAPI api.crl_path configuration points to the actual CRL file, not a certificate
Example fix
// before: non-atomic CRL update by cron wget -O /etc/crowdsec/ssl/crl.pem http://ca/crl.pem // after: atomic replace echo 'X509 CRL' >/dev/null; wget -O /etc/crowdsec/ssl/crl.pem.tmp http://ca/crl.pem && mv /etc/crowdsec/ssl/crl.pem.tmp /etc/crowdsec/ssl/crl.pem
Defensive patterns
Strategy: fallback
Validate before calling
// validate the CRL PEM before pointing crowdsec at it
b, _ := os.ReadFile(crlPath)
block, _ := pem.Decode(b)
if block == nil || _, err := x509.ParseRevocationList(block.Bytes); err != nil {
return fmt.Errorf("invalid CRL file %s: %w", crlPath, err)
} Type guard
func isValidPEMCRL(data []byte) bool {
block, _ := pem.Decode(data)
if block == nil {
return false
}
_, err := x509.ParseRevocationList(block.Bytes)
return err == nil
} Try / catch
if err := checker.Refresh(); err != nil {
if strings.Contains(err.Error(), "could not parse file") {
log.Warnf("CRL file invalid, keeping previous version: %v", err)
}
} Prevention
- Always publish CRLs as PEM 'X509 CRL' blocks only, never mixed with certificates
- Write CRL files atomically (temp file + rename) in CA rotation scripts
- Validate the CRL with 'openssl crl -in crl.pem -noout -text' after every regeneration
- Monitor CRL file contents after CA upgrades or tooling changes
When it happens
Trigger: refresh() reads the CRL file (after detecting a modtime/size change), passes bytes to decodeCRLs; a PEM block's DER payload fails x509.ParseRevocationList -> 'could not parse file: %w'. Caused by corrupt downloads, wrong PEM type (e.g. a certificate pasted in the CRL file), or an old CRL format.
Common situations: CA renewal scripts write partial/empty CRL files; user concatenates cert+CRL; TLS CRL generated with an outdated tool producing a v1 list; file truncated mid-download.
Related errors
- could not access CRL file: %w
- could not read CRL file: %w
- certificate revoked by CRL
- cannot use TLS with a unix socket
- user/password authentication and TLS authentication are mutu
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/467babc46530b30a.
Report an issue: GitHub.