siyuan-note/siyuan · error

createDocTree document title must not be empty

Error message

createDocTree document title must not be empty

What it means

After normalization (normalizeDocTitle trims whitespace and strips invalid characters), a title that normalizes to the empty string is rejected. Titles become file-system path segments for the new documents, so an empty title cannot produce a valid document path.

Source

Thrown at kernel/model/template_doc_tree.go:157

		for key := range definition {
			switch key {
			case "title", "template", "define", "children":
			default:
				return nil, fmt.Errorf("createDocTree document contains unknown field [%s]", key)
			}
		}

		titleValue, ok := definition["title"]
		if !ok {
			return nil, errors.New("createDocTree document title is required")
		}
		title, ok := titleValue.(string)
		if !ok {
			return nil, errors.New("createDocTree document title must be a string")
		}
		title = normalizeDocTitle(title)
		if "" == title {
			return nil, errors.New("createDocTree document title must not be empty")
		}
		if 512 < utf8.RuneCountInString(title) {
			return nil, fmt.Errorf("createDocTree document title exceeds %d characters", 512)
		}

		templateName, err := templateDocTreeStringField(definition, "template")
		if nil != err {
			return nil, err
		}
		defineName, err := templateDocTreeStringField(definition, "define")
		if nil != err {
			return nil, err
		}
		if "" != templateName && "" != defineName {
			return nil, errors.New("createDocTree document template and define are mutually exclusive")
		}

		state.count++

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Provide a non-empty title containing at least one valid character.
  2. Check that any template-variable interpolation in the title produces non-empty text at render time.
  3. Strip or replace characters that normalize away (/, \, control chars) with readable substitutes before rendering.
  4. Pre-validate titles: trim and reject empty/whitespace-only strings before invoking createDocTree.

Example fix

// before
{"title": "   "}
// after
{"title": "Untitled"}
Defensive patterns

Strategy: validation

Validate before calling

var walk func(nodes []any) error
walk = func(nodes []any) error {
    for _, v := range nodes {
        m, ok := v.(map[string]any)
        if !ok { continue }
        if t, ok := m["title"].(string); ok {
            if strings.TrimSpace(t) == "" {
                return errors.New("title must not be empty or whitespace")
            }
        }
        if c, ok := m["children"]; ok {
            if cl, ok := c.([]any); ok {
                if err := walk(cl); err != nil { return err }
            }
        }
    }
    return nil
}

Type guard

func hasNonEmptyTitle(v any) bool {
    m, ok := v.(map[string]any)
    if !ok { return false }
    t, ok := m["title"].(string)
    return ok && strings.TrimSpace(t) != ""
}

Try / catch

nodes, err := parseTemplateDocTreeDefinition(def)
if err != nil {
    if strings.Contains(err.Error(), "title must not be empty") {
        // substitute a default title and retry
    }
    return err
}

Prevention

When it happens

Trigger: A title of "" or only whitespace (" "); a title made entirely of characters removed by normalizeDocTitle (e.g. path separators or illegal filename characters); interpolation that yields an empty string at render time.

Common situations: Template placeholders like {{.Name}} that resolve to empty; authors using only slashes or dots in titles; data-driven generation where the source field is empty.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/4412b8a0e5655169. Report an issue: GitHub.