{"record":{"id":"c262fc910cb620ae","repo":"slackhq/nebula","slug":"errtruncatedpemblock","errorCode":"ErrTruncatedPEMBlock","errorMessage":"truncated PEM block","messagePattern":"truncated PEM block","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cert/pem.go","lineNumber":12,"sourceCode":"package cert\n\nimport (\n\t\"bytes\"\n\t\"encoding/pem\"\n\t\"errors\"\n\t\"fmt\"\n\n\t\"golang.org/x/crypto/ed25519\"\n)\n\nvar ErrTruncatedPEMBlock = errors.New(\"truncated PEM block\")\n\n// SplitPEM is a split function for bufio.Scanner that returns each PEM block.\nfunc SplitPEM(data []byte, atEOF bool) (advance int, token []byte, err error) {\n\t// Look for the start of a PEM block\n\tstart := bytes.Index(data, []byte(\"-----BEGIN \"))\n\tif start == -1 {\n\t\tif atEOF && len(bytes.TrimSpace(data)) > 0 {\n\t\t\t// Non-whitespace content with no PEM block\n\t\t\treturn 0, nil, ErrTruncatedPEMBlock\n\t\t}\n\t\tif atEOF {\n\t\t\treturn len(data), nil, nil\n\t\t}\n\t\t// Request more data\n\t\treturn 0, nil, nil\n\t}\n\n\t// Look for the end marker","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/slackhq/nebula/blob/dd8f660c0ac37903ec4080ca4d3c861ba9342ceb/cert/pem.go#L1-L30","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: file contains a half-pasted key\n-----BEGIN PRIVATE KEY-----\nMIIEvQ...\n(no END line)\n\n// after\n-----BEGIN PRIVATE KEY-----\nMIIEvQ...\n-----END PRIVATE KEY-----","handlingStrategy":"validation","validationCode":"if !bytes.Contains(data, []byte(\"-----BEGIN \")) || !bytes.Contains(data, []byte(\"-----END \")) {\n    return fmt.Errorf(\"PEM input incomplete or invalid\")\n}\nscanner := bufio.NewScanner(r)\nscanner.Split(cert.SplitPEM)\nfor scanner.Scan() { block, _ := pem.Decode(scanner.Bytes()); _ = block }\nif err := scanner.Err(); err != nil { return err }","typeGuard":"func isCompletePEM(data []byte) bool {\n    block, rest := pem.Decode(data)\n    return block != nil && len(rest) >= 0 && block.Type != \"\"\n}","tryCatchPattern":"if err := scanner.Err(); err != nil {\n    if errors.Is(err, cert.ErrTruncatedPEMBlock) {\n        return fmt.Errorf(\"certificate file malformed: %w\", err)\n    }\n    return err\n}","preventionTips":["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."],"tags":["pem","certificate","parsing","go"],"backgroundTag":"malformed-pem-block","analyzedSha":"dd8f660c0ac37903ec4080ca4d3c861ba9342ceb","analyzedAt":"2026-09-03T11:13:55.444Z","contentChangedAt":"2026-09-03T11:13:55.444Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}