Reference · 94 codes
Audit codes.
Patens runs a built-in audit module against every project. Each issue
it finds is reported with a stable code (e.g. sidebearing-deeply-negative-lsb) so it's referenceable in commits,
bug reports, and tutorials. This page is the canonical reference for
what every code means.
Codes are grouped by family. Each code in the editor links here, and many issues have a one-click Fix action available inline.
For the marketing-level explanation of why Patens has a teaching audit module — philosophy, comparison vs. other browser-based editors, CLI integration — see /audit.
Contour shape
Issues with the geometry of a glyph's outlines — control points, segments, intersections. These are catchable by the editor without any context about the font as a whole.
- open-contour
- A contour lacks its closing Z command. Open paths still rasterise but break boolean ops and many shaping tools. →
- duplicate-points
- Two consecutive on-curve points sit within 0.5fu of each other — the second adds no information and may cause hinting noise. →
- off-grid-points
- Point coordinates are fractional. Most renderers round to integer font units anyway — snapping explicitly avoids subpixel surprises. →
- near-collinear-points
- A point sits within 1fu of the line between its neighbours — a vestigial node, safe to remove. →
- sharp-kink
- A 5–25° turn between line segments. Probably meant to be a smooth curve or a clean corner. →
- self-intersecting
- A contour crosses itself. Rasterisers fill the overlap unpredictably depending on fill-rule (even-odd vs non-zero). →
- contour-winding-collision
- A nested counter shares its outer contour's direction. Inner contours must run opposite for the counter to render as a hole. →
- tiny-contour
- A contour smaller than 8fu in both dimensions — usually a stray artefact from a boolean op or imported SVG. →
Metric alignment
Whether letters that should reach the x-height, cap-height, ascender, or descender actually do. Inconsistent metric alignment is the most common reason a typeface reads as "wobbly" at body size.
- xheight-misaligned
- A lowercase letter that should reach x-height is sitting noticeably below it. Uneven tops across letters give text a wobbly rhythm; consistent x-height alignment is what makes type read smoothly. →
- capheight-misaligned
- An uppercase letter that should reach cap-height is sitting noticeably below it. Caps lines lose their crisp baseline-and-cap rhythm when individual letters fall short. →
- extends-above-ascender
- The glyph's bbox extends above the OS/2 ascender. Some renderers will clip the top stroke. →
- extends-below-descender
- The glyph's bbox extends below the OS/2 descender. Some renderers will clip the bottom stroke. →
Spacing & sidebearings
The horizontal layout of glyphs — advance widths, left and right sidebearings. These checks catch accidental overlaps, zero-width glyphs, and the negative sidebearings that creep in from mass-spacing passes.
- zero-advance
- The glyph's advance width is 0. Text containing this glyph will have all following glyphs stacked at the same position. →
- overflows-advance
- The drawn glyph extends past its advance width. Adjacent glyphs will overlap — bump the advance or pull the right edge in. →
- sidebearing-deeply-negative-lsb
- Left sidebearing is more negative than -100fu — usually a bug from a mass-spacing pass. Modest negatives (e.g. -20) are normal for italic letters that lean. →
- sidebearing-deeply-negative-rsb
- Right sidebearing is more negative than -100fu — usually a bug from a mass-spacing pass. Modest negatives (e.g. -20) are normal for italic letters that lean or for tightly-tucked terminal shapes (T, Y, V at the end of a word). →
- sidebearing-class-drift-lsb
- This glyph's left sidebearing has drifted from the median of its sidebearing-class peers. Either re-apply the class or remove this glyph from it. →
- sidebearing-class-drift-rsb
- This glyph's right sidebearing has drifted from the median of its sidebearing-class peers. Either re-apply the class or remove this glyph from it — the drift means one of those two is your intent, and leaving the class in place propagates the staleness on the next class edit. →
- sidebearings-no-classes
- The project has no sidebearing classes — every glyph carries its sidebearings independently. For mid-to-large families this gets unmaintainable; sidebearing classes pin shape-similar glyphs (n / m / h / b / d / p / q) together so a tweak propagates. →
Composites & references
Composite glyphs are built from component references — Á is A plus the acute mark. These checks catch broken references and infinite-loop component cycles.
- composite-cycle
- A composite glyph references itself transitively (A → B → A). Rendering would loop forever — exports break. Remove one link in the chain. →
- composite-missing-base
- A composite reference points at a glyph with no outlines. The reference will render as nothing. →
Anchors & mark positioning
GPOS mark positioning relies on named anchors — base glyphs declare anchor names (top, bottom), marks declare matching partner names (_top, _bottom). These checks enforce the naming contract and the partner requirement.
- anchors-missing
- A meaningful number of Latin base glyphs have no anchors. Composites built from them (Á, È, Ñ, Ç) will use fixed offsets rather than proper GPOS mark positioning — marks will look mechanically placed rather than tuned to each letter's shape. →
- anchor-without-partner
- An anchor has no partner on the other side (no mark with the matching "_name" for a base anchor, or no base with the matching "name" for a mark anchor). Info-level because designers often add anchors ahead of drawing the partner glyph — but if you forget the partner, the anchor sits unused at export. →
- anchor-naming-base-with-prefix
- Base-glyph anchors should not start with "_" — that prefix is reserved for mark glyphs. Rename or the GPOS mark feature will miss this attachment point. →
- anchor-naming-mark-no-prefix
- GPOS mark-positioning convention: marks (combining diacritics) carry anchors prefixed with "_" so they pair up with same-named base anchors. Without the prefix, this anchor never enters the mark feature. →
OpenType features
Auto-detected OpenType feature integrity — kerning, classes, pair coverage.
- feature-kern-disabled-with-pairs
- The kern feature is disabled in project.features.kern but kerning pairs exist in project.kerning. The pairs ship in the OTF dead — they're emitted into the file but the off flag tells renderers to skip them. Either enable kern on the Features tab (the typical case once pairs are set) or delete the pair data. →
- figures-non-tabular
- The 0–9 digits have unequal advance widths — proportional figures. Fine for body text; broken for data tables, prices, and spreadsheets where columns of numbers must align. Run "Tabularise 0–9" on the Spacing tab to give every digit the same advance. →
- kerning-no-classes
- The project has many flat kerning pairs and zero kerning classes. Once you have more than ~30 pairs, classes become much more maintainable than direct pairs — grouping accented variants (e.g. @A_left = [A Á Â Ä À]) consolidates kerning across the family. →
- kerning-class-singleton
- A kerning class has exactly one member. Classes are meant to group glyphs that share kerning behavior — a singleton class is identical to a direct pair and just adds a layer to navigate. Either expand it (e.g. visually-similar glyphs to share the value) or replace it with a direct pair on the spacing tab. →
- kerning-extreme
- A kerning pair exceeds half the smaller glyph's advance — almost certainly a decimal typo (e.g. -500 typed when -50 was meant). Check the value in the spacing pair editor. →
- kerning-pair-self
- A kerning pair sets a value where the left and right glyph are the same — at run time this pulls a letter toward itself, which is rarely intended. Usually a typo in the pair editor (accidentally entering the same glyph in both slots). Delete unless the script genuinely needs self-kerning in a compound context. →
- pair-missing-glyph
- A kerning pair references a glyph that doesn't exist in the project. The pair is dead weight — either draw the missing glyph or remove the pair from the spacing tab. →
- pair-orphan-class
- A kerning pair references an undefined kerning class. The pair silently does nothing at run time. Either define the class or change the pair to reference one that exists. →
- class-empty
- A kerning class has no members. Empty classes pull their weight on the maintenance side but contribute nothing at run time — either fill them with the glyphs they're meant to group, or delete them. →
- class-missing-member
- A kerning class lists a codepoint that has no corresponding glyph in the project. The reference is dead — the class behaves as if that member weren't there. Either draw the glyph or remove the reference from the class. →
- class-name-format
- A kerning class name doesn't start with "@" — the convention shared by Glyphs, FontLab, and FEA syntax for kerning groups. Renaming makes the class read uniformly across tools and any FEA you generate. →
Glyph naming
Glyph names follow specific rules (production names per Adobe glyph list, length limits, character restrictions). Renderers and font shells fall back to .notdef when names are malformed.
- glyph-name-empty
- Glyph name field is empty. PostScript glyph names are required for OpenType feature substitutions. →
- glyph-name-invalid
- Glyph name contains characters outside the allowed set (A-Za-z0-9._-) or starts with a digit. The PostScript spec forbids it. →
- glyph-name-not-canonical
- The glyph name differs from the canonical Adobe Glyph List for New Fonts name for this codepoint. Renaming keeps downstream tooling (feature substitutions, color emoji lookups, PostScript naming) consistent. →
- glyph-name-too-long
- Glyph name exceeds 63 characters. The OpenType post-table v2 spec caps individual names at 63 bytes; longer names get silently truncated on export, which can then collide with whatever existing glyph already shares the prefix. Use the AGLFN suggestion chip in the glyph browser to get a canonical short name. →
- duplicate-glyph-name
- Two or more glyphs share the same PostScript name. The OpenType post table requires unique names — OTF export fails. Rename the conflicting glyphs (the AGLFN suggestion chip + bulk AGLFN rename in the glyph browser are the fastest paths). →
Vertical metrics
OS/2 and hhea tables hold the vertical metrics renderers use. These two tables must agree or text reflows inconsistently between OS/browser combinations.
- metrics-asc-mismatch
- OS/2 typoAscender doesn't match hhea ascender. The two values should be equal — line-height computations on Mac/iOS read OS/2, on Windows browsers read hhea, and a mismatch causes line spacing to differ across platforms. →
- metrics-desc-mismatch
- OS/2 typoDescender doesn't match hhea descender. Same platform-divergence story as the ascender mismatch — line spacing won't match between Mac and Windows. →
- metrics-gap-mismatch
- OS/2 typoLineGap doesn't match hhea lineGap. The extra-line-gap above the ascender is platform-dependent unless both fields agree. Set them equal in the Metrics inspector. →
- metrics-use-typo-off
- The USE_TYPO_METRICS flag (OS/2 fsSelection bit 7) is off. Without it, Windows uses winAscent / winDescent for line spacing while Mac uses typoAscender / typoDescender, producing different line heights across platforms. Almost always should be on. →
- metrics-cap-above-ascender
- Cap-height exceeds the ascender. Capital letters will clip when rendered — ascender is the platform-recognised top of the glyph bounding box, caps must fit inside it. →
- metrics-x-above-cap
- x-height exceeds cap-height — lowercase letters would render taller than uppercase. Almost certainly a typo in the metrics inspector. →
- metrics-descender-nonnegative
- Descender is zero or positive — descending letters (g, j, p, q, y) will sit on the baseline rather than dropping below it. Descender values are conventionally negative (e.g. -200 at 1000 UPM). →
- metrics-win-clip-top
- OS/2 winAscent is below typoAscender — top edges of glyphs may clip on Windows. winAscent is Windows' clipping boundary; if it sits below the typoAscender, ascenders that reach typoAscender will be cropped. Bump winAscent up. →
- metrics-win-clip-bottom
- OS/2 winDescent is below |typoDescender| — descenders may clip on Windows. winDescent is the clipping boundary for descenders; if it's smaller than the typoDescender's magnitude, descenders get cropped. Bump winDescent up. →
- metrics-zero-height
- Cap-height or x-height is zero. Several algorithms (auto-spacing, spacing-by-reference, x-height alignment audit) depend on these to be positive — set them in the metrics inspector. →
Font metadata
The OS/2 + name-table fields a real shippable font needs — designer, manufacturer, license, vendor ID, version string, copyright.
- meta-no-designer
- Designer field is empty. Name table ID 9 ships blank, so Glyphs / Font Book / OS font browsers show "Unknown designer". Set it on the Brief tab. →
- meta-no-designer-url
- Designer URL is empty. A homepage or portfolio link surfaces in some font dialogs and in PDF metadata when the font is embedded. Recommended for any font you want credit on. →
- meta-no-manufacturer
- Manufacturer (foundry) field is empty — the name table falls back to the designer name. If you ship under a foundry brand distinct from the designer, set it explicitly so attribution is correct. →
- meta-no-license
- License field is empty. Pick a preset on the Export tab (OFL 1.1 for open source, Proprietary for commercial) so downstream users know the terms — fonts without licenses get treated as untrusted by review tools. →
- meta-no-license-url
- License is set but the license URL is empty. URLs let embedded apps link directly to the license text (e.g. https://scripts.sil.org/OFL for OFL). Strongly recommended for OFL fonts. →
- meta-no-copyright
- Copyright notice is empty. Most foundries require it; Google Fonts review rejects fonts without one. Add a one-line copyright on the Export tab (e.g. "Copyright 2026 Your Name"). →
- meta-no-vendor-id
- OS/2 vendor ID is empty — defaults to "NONE" in the exported file. Register a 4-letter foundry tag at https://learn.microsoft.com/typography/vendors/ to identify your fonts in font-management tooling and crash diagnostics. →
- meta-vendor-id-invalid
- Vendor ID is more than 4 characters or contains non-ASCII. The OS/2 achVendID field is 4 bytes — Microsoft's registry uses 4-letter all-caps tags. Short tags will be space-padded; over-length tags get truncated. →
- meta-version-format
- Version string doesn't match the OpenType "MAJOR.MINOR" convention (e.g. "1.000", "2.345"). Many tools parse it into head.fontRevision and round non-conforming strings — best to follow the convention for predictable behavior. →
- naming-family
- Family name is empty. The OpenType name table requires a non-empty family name (ID 1) — export will refuse to produce a file without it. Set it on the Brief or Export tab. →
- naming-family-chars
- Family name contains characters outside the safe set (letters / digits / space / hyphen). Some apps reject anything beyond that — limit to A–Z, a–z, 0–9, space, and hyphen unless you've verified your target apps accept more. →
- naming-family-long
- Family name exceeds 31 characters. Some legacy app menus truncate or refuse to list overly long family names — keeping the name compact avoids ugly fallback behavior in Word, Photoshop, and older Office builds. →
- naming-style
- Style name is empty. The name table requires a style name (ID 2 — e.g. "Regular", "Bold", "Italic"). Export refuses to ship without one. →
- naming-version
- Version field is empty. The OpenType head.fontRevision is derived from this — when empty, export defaults to "1.000". Set it explicitly so each release has a recognisable version string in font dialogs. →
- naming-copyright-missing
- Copyright line is empty. Recommended for any distributed font — sets ownership and reuse boundaries. →
- naming-designer-missing
- Designer field is empty. The name appears in OS font browsers and any metadata-aware tool — leaving it blank shows "Unknown". →
- naming-license-missing
- License field is empty. Distributing without a license leaves recipients guessing about terms. Pick an SPDX identifier (e.g. "OFL-1.1") or paste your custom EULA. →
Design brief
Brief completeness — design intent, audience, motivation. The brief drives later editorial decisions and is what makes audit results contextual ("this typeface's brief says 'large display', so a too-thin hairline matters here").
- brief-no-intent
- The brief's "intent" field is empty. Without a stated intent, audit and review tools can't check whether design choices match the goal. Set one sentence on the Brief tab — e.g. "a geometric sans for product UI at 14px+". →
- brief-no-design-notes
- The brief has no design notes. Notes are where you record decisions ("contrast is monoline", "g is single-storey") so future-you doesn't reinvent them. Not required for export — recommended for any project you'll revisit. →
- notes-todo
- The glyph's notes field contains TODO or FIXME — an unresolved work item the designer left for future iteration. →
- flagged-for-review
- A designer hit Shift+F on this glyph to mark it for follow-up review — a designer-set reminder, not a rule violation. The flag clears with another Shift+F. Useful for batch-marking glyphs that need refinement on a second pass without losing track (e.g. the bespoke Cyrillic shapes Я Ж Ф that ship as sketches in the demo project). →
Variable fonts & axes
Designspace integrity for variable fonts — axes, masters, instances. These checks fire when an axis is declared but unused, a master is out of range, or an instance points at an axis that no longer exists.
- axis-range-invalid
- A designspace axis has min/default/max values out of order. The interpolation engine requires min ≤ default ≤ max — fix the axis on the Designspace tab. →
- master-axis-missing
- A master is missing a value for a declared axis. Interpolation is undefined at that axis — the export pipeline will substitute the axis default, which is rarely what the designer intended. →
- master-axis-unknown
- A master's location references an axis tag the project doesn't declare. The unknown axis is ignored at export — fix by adding the axis to project.axes or removing it from the master's location. →
- master-axis-out-of-range
- A master's axis value sits outside the declared range. The interpolation engine will clip to the nearest valid value, producing unexpected geometry. →
- master-orphan-axis
- A master references an axis the project doesn't declare. The unknown axis is ignored at export, which may produce unexpected interpolation results. Either remove the axis reference from the master's location or add the axis to project.axes. →
- master-out-of-range
- A master's axis value sits outside the declared range. Interpolation will clip to the nearest valid value, producing unexpected geometry. Either move the master into range or widen the axis range to include it. →
- master-empty
- A variable-font master has no glyph overrides — every codepoint falls back to the default master's shape. Either add at least one override (the typical case: the difference is what defines the master) or remove the master from the designspace. →
- master-contour-count
- The number of contours differs across masters. VF interpolation requires identical contour count and order in every master. →
- master-point-count
- A specific contour has different point counts across masters. Same constraint as master-contour-count, one level deeper. →
- instance-orphan-axis
- A named instance references an axis the project doesn't declare. The instance will fall back to axis defaults for the unknown axis — usually not what you want. Remove or re-tag the axis reference. →
- no-instances
- The designspace has axes but no named instances. Most apps expect at least the default instance to be defined (e.g. "Regular") so users have something to pick from the font menu. Add one on the Designspace tab. →
Multi-script coverage
Whether a project that declares a script has enough glyphs to be useful in that script. Patens has bulk-coverage codes for Latin-1, currency, math, typographic essentials, and control glyphs.
- coverage-latin-1-supp
- The Latin-1 Supplement subset is incomplete — accented letters used across Western European languages (À É Ñ Ü etc.). Missing glyphs mean Spanish, French, German, Portuguese, etc. won't render in your font. →
- coverage-currency
- The currency-symbol subset is incomplete (¥ £ € ¢ ¤ etc.). Missing currency glyphs fall back to system fonts in price text — a visible inconsistency on storefronts and invoices. →
- coverage-math
- The math-symbol subset is incomplete (± × ÷ ≠ ≤ ≥ etc.). Missing math glyphs are mostly invisible in body text but show up sharply in data tables and technical writing. →
- coverage-typo-essentials
- The typographic essentials subset is incomplete — basic punctuation and spacing characters that every font needs to feel finished (period, comma, hyphen, space, colon, semicolon, quotes). Some text will render with system-font fallbacks for the missing glyphs. →
- control-glyphs-missing
- The 12-glyph control set (the letters foundries draw first to establish proportion + texture: H, O, n, o, +, period, etc.) is incomplete. These should land before mass-drawing the rest because they set the visual rhythm everything else has to match. →
- glyph-count-low
- The project has fewer than ~95 drawn glyphs — the baseline for "usable font" (A–Z + a–z + 0–9 + basic punctuation). Below that, most real-world text will render with fallback fonts mixed in. →
Color fonts
COLR / CPAL integrity — palette indices in COLR layers must exist in CPAL.
- color-layer-no-palette
- A glyph carries color layers but the project has no palettes defined — the layers won't render. Either define a palette on the Features tab so the layers have somewhere to draw their colors from, or remove the colorLayers from the glyph if the color was experimental. →
- color-layer-out-of-range
- A color layer references a palette slot index that's beyond the shortest palette's color count. That layer renders transparent in any palette that doesn't have a color at that index. Either add more colors to the short palette(s) or change the layer to reference a slot within the existing range. →
- palette-length-mismatch
- Color palettes have different lengths. CPAL requires every palette to share the same color count — when a glyph layer references slot 4 and only the default palette has 5 colors, the alternate palette will fail to render that layer. Trim or pad palettes on the features tab so all share one length. →
UPM
Units per em — the font's coordinate grid. Unusual values cause rendering edge cases.
- upm-unusual
- Units-per-em (UPM) sits outside the typical 1000–2048 range. Most foundries pick 1000 (PostScript convention) or 2048 (TrueType convention). Unusual values still work but may cause off-by-one rounding when other tools assume a standard UPM. →
If a code is missing or its description doesn't match what you see in the editor, email hi@patens.design. Accuracy here is the difference between the audit module feeling like a teaching tool and feeling like noise.