slackhq/nebula · error
ErrTruncatedPEMBlock
ErrTruncatedPEMBlock
Error message
truncated PEM block
What it means
ErrTruncatedPEMBlock is returned by SplitPEM, a bufio.Scanner split function in cert/pem.go, when it encounters non-whitespace data that does not form a complete PEM block. It is raised at EOF either because no '-----BEGIN ' marker was found at all (only garbage), or because a block was started but never closed before the input ended. It signals malformed certificate/key material rather than a transient I/O problem.
Source
Thrown at cert/pem.go:12
package cert
import (
"bytes"
"encoding/pem"
"errors"
"fmt"
"golang.org/x/crypto/ed25519"
)
var ErrTruncatedPEMBlock = errors.New("truncated PEM block")
// SplitPEM is a split function for bufio.Scanner that returns each PEM block.
func SplitPEM(data []byte, atEOF bool) (advance int, token []byte, err error) {
// Look for the start of a PEM block
start := bytes.Index(data, []byte("-----BEGIN "))
if start == -1 {
if atEOF && len(bytes.TrimSpace(data)) > 0 {
// Non-whitespace content with no PEM block
return 0, nil, ErrTruncatedPEMBlock
}
if atEOF {
return len(data), nil, nil
}
// Request more data
return 0, nil, nil
}
// Look for the end markerView on GitHub (pinned to dd8f660c0a)
Solutions
- Open the file at the reported offset and remove any non-PEM text that is not inside a complete -----BEGIN/-----END block.
- Re-export or re-download the certificate/key so the PEM block includes its closing '-----END ...-----' line.
- If garbage is intentionally present (e.g. comments), pre-strip it or treat scanner.Err() accordingly and skip that region.
- Verify file integrity (checksums) to rule out truncated transfers.
Example fix
// before: file contains a half-pasted key -----BEGIN PRIVATE KEY----- MIIEvQ... (no END line) // after -----BEGIN PRIVATE KEY----- MIIEvQ... -----END PRIVATE KEY-----
Defensive patterns
Strategy: validation
Validate before calling
if !bytes.Contains(data, []byte("-----BEGIN ")) || !bytes.Contains(data, []byte("-----END ")) {
return fmt.Errorf("PEM input incomplete or invalid")
}
scanner := bufio.NewScanner(r)
scanner.Split(cert.SplitPEM)
for scanner.Scan() { block, _ := pem.Decode(scanner.Bytes()); _ = block }
if err := scanner.Err(); err != nil { return err } Type guard
func isCompletePEM(data []byte) bool {
block, rest := pem.Decode(data)
return block != nil && len(rest) >= 0 && block.Type != ""
} Try / catch
if err := scanner.Err(); err != nil {
if errors.Is(err, cert.ErrTruncatedPEMBlock) {
return fmt.Errorf("certificate file malformed: %w", err)
}
return err
} Prevention
- Validate PEM files with openssl or pem.Decode before feeding them to the scanner.
- Never hand-edit certificate files; always re-export from the source.
- Checksum-verify downloaded certs/keys to catch truncation.
- Strip trailing garbage from concatenated PEM bundles at build/deploy time.
When it happens
Trigger: Scanning PEM data where at EOF there is leftover non-whitespace text with no '-----BEGIN ' marker (cert/pem.go:21), or scanning data where an incomplete PEM block remains when EOF is reached (cert/pem.go:35). Returned by SplitPEM via bufio.Scanner; surfaced in tests TestSplitPEM_TrailingGarbage, TestSplitPEM_TruncatedBlock, TestSplitPEM_GarbageOnly.
Common situations: Config or CA file containing trailing garbage after valid PEM blocks; a certificate file that was copy-pasted and lost its '-----END ...-----' line; concatenating files where a non-PEM blob (e.g. base64-only output, a JSON blob) was appended; download truncation of a key file.
Related errors
- input did not contain a valid PEM encoded block
- input did not contain a valid PEM encoded block
- error while unmarshaling cert: %s
- error while marshalling certificate: %s
- ErrBadFormat
AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03).
Data as JSON: /api/errors/c262fc910cb620ae.
Report an issue: GitHub.