{"record":{"id":"2e32f29adfb7f98e","repo":"d2lang/d2","slug":"invalid-font-collection-offset","errorCode":null,"errorMessage":"invalid font collection offset","messagePattern":"invalid font collection offset","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/textmeasure/fontface.go","lineNumber":201,"sourceCode":"\t\t\tvalue: int16(binary.BigEndian.Uint16(table[offset+4 : offset+6])),\n\t\t}\n\t}\n\treturn pairs, nil\n}\n\nfunc sfntTable(src []byte, tag string) ([]byte, error) {\n\tif len(src) < 12 {\n\t\treturn nil, fmt.Errorf(\"invalid sfnt: too short\")\n\t}\n\n\tbase := 0\n\tif string(src[:4]) == \"ttcf\" {\n\t\tif len(src) < 16 || binary.BigEndian.Uint32(src[8:12]) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"invalid font collection\")\n\t\t}\n\t\tbase = int(binary.BigEndian.Uint32(src[12:16]))\n\t\tif base < 0 || base+12 > len(src) {\n\t\t\treturn nil, fmt.Errorf(\"invalid font collection offset\")\n\t\t}\n\t}\n\n\tn := int(binary.BigEndian.Uint16(src[base+4 : base+6]))\n\trecords := base + 12\n\tif n > (len(src)-records)/16 {\n\t\treturn nil, fmt.Errorf(\"invalid sfnt table directory\")\n\t}\n\tfor i := 0; i < n; i++ {\n\t\trecord := src[records+16*i : records+16*(i+1)]\n\t\tif string(record[:4]) != tag {\n\t\t\tcontinue\n\t\t}\n\t\toffset := int(binary.BigEndian.Uint32(record[8:12]))\n\t\tlength := int(binary.BigEndian.Uint32(record[12:16]))\n\t\tif offset < 0 || length < 0 || offset > len(src)-length {\n\t\t\treturn nil, fmt.Errorf(\"invalid %s table bounds\", tag)\n\t\t}","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/d2lang/d2/blob/0d69dca6f532ceaeacd615d35d1eaa41a238ffdb/lib/textmeasure/fontface.go#L183-L219","documentation":"After reading the ttcf header, the first font's offset (bytes 12–16) is taken as the base; base must be non-negative and leave room for a 12-byte sfnt header within the data. An out-of-range offset means the collection header lies about where its first font begins.","triggerScenarios":"parseFont on a .ttc whose first-font offset points before the start of the file or past the point where a 12-byte sfnt header would fit.","commonSituations":"Tampered or corrupted .ttc files; endianness/parse mistakes from pre-processing tools; truncated collections whose offset was not adjusted.","solutions":["Regenerate the .ttc with a reliable tool (fonttools ttCollection) or use the individual .ttf files.","Verify the font data integrity (size, checksum) before loading.","Validate offsets yourself with a quick binary check before passing the data to the library."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"func ttcOffsetInRange(data []byte) bool {\n    if string(data[:4]) != \"ttcf\" || len(data) < 16 { return false }\n    base := int(binary.BigEndian.Uint32(data[12:16]))\n    return base >= 0 && base+12 <= len(data)\n}","typeGuard":null,"tryCatchPattern":"if err := loadAndParseFont(path); err != nil {\n    log.Printf(\"bad font collection offset in %s: %v\", path, err)\n    return loadSingleFont(fallbackPath)\n}","preventionTips":["Never hand-edit font binaries; rebuild collections with proper tooling","Validate collection offsets before passing font data to the parser","Keep canonical font sources under version control with checksums","Test font loading in CI to catch corrupted assets before deployment"],"tags":["font","ttc","corrupt-file"],"backgroundTag":"invalid-font-file","analyzedSha":"0d69dca6f532ceaeacd615d35d1eaa41a238ffdb","analyzedAt":"2026-08-31T12:19:21.182Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}