Skip to content

Validation Guide

Use .validate() to catch structural and cross-table issues before export. The validator also auto-fixes recoverable problems (missing headers, wrong directory fields, mismatched counts) and reports them as info-level issues so the font can be exported directly afterward.

API

js
import { FontFlux } from 'font-flux-js';

const font = FontFlux.open(buffer);

const report = font.validate();
// The internal data may have been mutated with auto-fixes
if (!report.valid) {
	console.error(report.errors);
	throw new Error('Font failed validation');
}

const output = font.export();

Severity levels

LevelMeaningEffect on valid
errorStructural problem that will prevent exportvalid = false
warningLikely bug or unusual condition; export may still succeedno effect
infoAuto-fixed or informational; no action neededno effect

What .validate() checks

  • Root shape (header, tables) for single fonts, or collection + fonts[] for TTC/OTC.
  • Header field sanity (sfVersion, numTables, directory fields) — auto-fixed when possible.
  • Table tags are exactly 4 characters.
  • Raw table bytes (_raw) are valid byte arrays.
  • Parsed table support (unknown parsed tables must use _raw).
  • Core table presence (cmap, head, hhea, hmtx, maxp, name, post).
  • Outline requirements:
    • TrueType outline requires both glyf and loca.
    • CFF outline uses CFF or CFF2.
  • Common cross-table dependencies (for parsed tables), such as:
    • hmtxhhea, maxp
    • locahead, maxp
    • glyfloca, head, maxp
    • vmtxvhea, maxp

Complete issue reference

Errors

CodeMessageWhen
INPUT_INVALIDvalidate expects a font JSON objectInput is not a plain object
FONTDATA_INVALIDFont data must be an objectFont entry (single or within collection) is not an object
TABLES_MISSINGFont tables are requiredtables missing or not an object
TABLES_EMPTYFont tables object is emptytables has zero entries
TABLE_TAG_INVALIDTable tag must be exactly 4 charactersA key in tables is not a 4-char string
TABLE_DATA_INVALIDTable must be an objectA table entry is not a plain object
TABLE_CHECKSUM_INVALID_checksum must be uint32_checksum is present but not a valid uint32
TABLE_RAW_INVALID_TYPE_raw must be an array of byte values_raw is not an array
TABLE_RAW_INVALID_BYTE_raw byte must be 0-255A value in _raw is out of byte range
TABLE_WRITER_UNSUPPORTEDParsed JSON but no writer availableUnrecognized table tag with parsed data (no _raw)
TABLE_DEPENDENCY_MISSINGParsed table requires another tableA parsed table's dependency is missing
REQUIRED_TABLE_MISSINGRequired core table missingOne of the 7 required core tables is absent
OUTLINE_MISSINGNo outline tables foundNeither TrueType nor CFF outline tables present
TRUETYPE_OUTLINE_INCOMPLETETrueType outline requires glyf/locaglyf or loca present without the other
HEADER_NUMTABLES_INVALIDnumTables must be a non-negative integernumTables is present but not a valid integer
COLLECTION_META_INVALIDcollection must be an objectCollection metadata is not an object
COLLECTION_FONTS_INVALIDfonts must be a non-empty arrayfonts is missing or empty in a collection

Warnings

CodeMessageWhen
RECOMMENDED_TABLE_MISSINGRecommended table "OS/2" is missingOS/2 table absent
MULTIPLE_OUTLINE_TYPESBoth TrueType and CFF presentBoth outline types coexist
VARIABLE_TABLE_DEPENDENCYgvar/cvar usually expects fvarVariable font table without axes definition

Info (auto-fixed or informational)

CodeMessageWhen
HEADER_SYNTHESIZEDNo header found; synthesized oneNeither header nor _header present; built from table data
HEADER_PROMOTEDPromoted "_header" for export compatibilityNo header but _header exists (e.g. after FontFlux.fromJSON())
HEADER_SFVERSION_INFERREDsfVersion inferred from outline tablessfVersion missing or invalid; inferred as 0x00010000 (TrueType) or 0x4F54544F (CFF)
HEADER_NUMTABLES_CORRECTEDnumTables corrected to match table countnumTables missing or does not match actual table count
HEADER_FIELDS_CORRECTEDDirectory fields auto-correctedsearchRange/entrySelector/rangeShift computed for actual table count
COLLECTION_NUMFONTS_CORRECTEDnumFonts corrected to match fonts arrayCollection numFonts does not match fonts.length
TABLE_UNRECOGNIZED_RAWUnrecognized table preserved via _rawUnknown tag with _raw — harmless, just noting it

Report format

js
{
  valid: false,
  errors:   [{ code, message, path, severity: 'error'   }],
  warnings: [{ code, message, path, severity: 'warning' }],
  infos:    [{ code, message, path, severity: 'info'    }],
  issues:   [...],  // all of the above combined
  summary: { errorCount, warningCount, infoCount, issueCount }
}

Auto-fix behavior

When .validate() detects a recoverable issue it mutates the input object in place and reports an info-level issue. This means the font can be exported directly after validation:

js
const report = font.validate();
// Internal data is now guaranteed to have correct header fields
if (report.valid) {
	const buffer = font.export();
}

Auto-fixes applied:

  • Missing header: Synthesized from table data (sfVersion inferred from CFF/TrueType tables).
  • _header promotion: Copied to header when header is absent.
  • Missing/wrong sfVersion: Inferred from outline tables.
  • numTables mismatch: Set to actual Object.keys(tables).length.
  • Directory fields: searchRange, entrySelector, rangeShift recomputed.
  • Collection numFonts: Corrected to match fonts.length.

Best practices

  • Run .validate() before every .export() call to catch issues early and apply auto-fixes.
  • Treat warnings as "likely bugs" when hand-authoring JSON.
  • Keep _raw for unknown tables to preserve round-trip behavior.
  • Prefer small iterative edits and validate after each edit.