d2lang/d2 · error
text not pre-measured and no ruler provided
Error message
text not pre-measured and no ruler provided
What it means
GetTextDimensionsWithMono reached its terminal fallback: the text was not found in the pre-measured mtexts list, the ruler is nil (or couldn't measure), and the trimmed text is non-empty. It returns this sentinel error meaning measurement was impossible — callers like the label/edge sizing paths surface it or treat nil as 'not found'.
Source
Thrown at d2graph/d2graph.go:1453
func getMarkdownDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2target.MText, fontFamily *d2fonts.FontFamily, monoFontFamily *d2fonts.FontFamily) (*d2target.TextDimensions, error) {
if dims := findMeasured(mtexts, t); dims != nil {
return dims, nil
}
if ruler != nil {
width, height, err := textmeasure.MeasureMarkdown(t.Text, ruler, fontFamily, monoFontFamily, t.FontSize)
if err != nil {
return nil, err
}
return d2target.NewTextDimensions(width, height), nil
}
if strings.TrimSpace(t.Text) == "" {
return d2target.NewTextDimensions(1, 1), nil
}
return nil, fmt.Errorf("text not pre-measured and no ruler provided")
}
func GetTextDimensions(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2target.MText, fontFamily *d2fonts.FontFamily) *d2target.TextDimensions {
return GetTextDimensionsWithMono(mtexts, ruler, t, fontFamily, nil)
}
func GetTextDimensionsWithMono(mtexts []*d2target.MText, ruler *textmeasure.Ruler, t *d2target.MText, fontFamily *d2fonts.FontFamily, monoFontFamily *d2fonts.FontFamily) *d2target.TextDimensions {
if dims := findMeasured(mtexts, t); dims != nil {
return dims
}
if ruler != nil {
var w int
var h int
if t.Language != "" {
originalLineHeight := ruler.LineHeightFactor
ruler.LineHeightFactor = textmeasure.CODE_LINE_HEIGHT
if monoFontFamily != nil {View on GitHub (pinned to 0d69dca6f5)
Solutions
- Create and pass a textmeasure.Ruler (textmeasure.NewRuler() with fonts initialized) so text is measured on demand
- Ensure mtexts contains an exact MText match — same Text, FontSize, fontFamily, bold/italic — for every measured string
- Regenerate mtexts via graph.SetText after any text or style change
- If the text can legitimately be empty, it's already handled: empty/whitespace text returns 1x1 dimensions without error
Example fix
// before dims := d2graph.GetTextDimensions(mtexts, nil, mt, fontFamily) // after ruler, _ := textmeasure.NewRuler() dims := d2graph.GetTextDimensions(mtexts, ruler, mt, fontFamily)
Defensive patterns
Strategy: validation
Validate before calling
// guard before calling GetTextDimensions without a ruler
func measure(mtexts []*d2target.MText, t *d2target.MText, ff *d2fonts.FontFamily) (*d2target.TextDimensions, error) {
if strings.TrimSpace(t.Text) == "" {
return d2target.NewTextDimensions(1, 1), nil
}
if ruler == nil {
for _, mt := range mtexts {
if mt.Text == t.Text && mt.FontSize == t.FontSize {
// only safe if an exact pre-measured entry exists
return d2target.NewTextDimensions(mt.Width, mt.Height), nil
}
}
return nil, fmt.Errorf("text %q not pre-measured; ruler required", t.Text)
}
return d2graph.GetTextDimensions(mtexts, ruler, t, ff), nil
} Type guard
func isPreMeasured(mtexts []*d2target.MText, t *d2target.MText) bool {
for _, mt := range mtexts {
if mt.Text == t.Text && mt.FontSize == t.FontSize &&
mt.FontFamily == t.FontFamily && mt.Bold == t.Bold && mt.Italic == t.Italic {
return true
}
}
return false
} Try / catch
dims := d2graph.GetTextDimensions(mtexts, ruler, mt, fontFamily)
if dims == nil {
return fmt.Errorf("text %q not pre-measured and no ruler provided", mt.Text)
} Prevention
- Always initialize a textmeasure.Ruler and pass it; nil rulers only work if every string is pre-measured
- Match MText fields exactly (text, size, family, bold/italic) when pre-measuring
- Call graph.SetText after graph construction so mtexts is complete
- Never assume whitespace-only text needs measurement — it short-circuits to 1x1
When it happens
Trigger: Calling GetTextDimensions/GetTextDimensionsWithMono with a nil ruler for a non-empty text that has no matching entry in mtexts (same text, fontSize, font family, and bold/italic flags).
Common situations: Embedding d2graph without textmeasure (e.g. no fonts bundled); passing mtexts generated before text/font changes; mismatched MText attributes causing lookup misses; custom render pipelines skipping graph.SetText.
Related errors
- dimensions for object label %#v not found
- dimensions for class field %#v not found
- dimensions for class method %#v not found
- dimensions for sql_table name %#v not found
- dimensions for sql_table type %#v not found
AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31).
Data as JSON: /api/errors/a01ae49eef3e76fb.
Report an issue: GitHub.