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 marker

View on GitHub (pinned to dd8f660c0a)

Solutions

  1. Open the file at the reported offset and remove any non-PEM text that is not inside a complete -----BEGIN/-----END block.
  2. Re-export or re-download the certificate/key so the PEM block includes its closing '-----END ...-----' line.
  3. If garbage is intentionally present (e.g. comments), pre-strip it or treat scanner.Err() accordingly and skip that region.
  4. 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

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


AI-assisted analysis of slackhq/nebula@dd8f660c0a (2026-09-03). Data as JSON: /api/errors/c262fc910cb620ae. Report an issue: GitHub.