siyuan-note/siyuan · error

createDocTree is only available when manually inserting a te

Error message

createDocTree is only available when manually inserting a template in the editor

What it means

The createDocTree template action may only run inside a collector that is both enabled and flagged allowCreation, which the kernel sets only when a user manually inserts a template into the editor. When create() is invoked in any other context (not enabled, or enabled for preview/render only), it refuses with this error. This prevents templates from creating documents during passive renders such as previews or template listing.

Source

Thrown at kernel/model/template_doc_tree.go:218

func templateDocTreeStringField(definition map[string]any, key string) (string, error) {
	value, exists := definition[key]
	if !exists {
		return "", nil
	}
	ret, ok := value.(string)
	if !ok {
		return "", fmt.Errorf("createDocTree document %s must be a string", key)
	}
	ret = strings.TrimSpace(ret)
	if "" == ret {
		return "", fmt.Errorf("createDocTree document %s must not be empty", key)
	}
	return ret, nil
}

func (collector *templateDocTreeCollector) create(def any) (string, error) {
	if !collector.enabled || !collector.allowCreation {
		return "", errors.New("createDocTree is only available when manually inserting a template in the editor")
	}
	nodes, err := parseTemplateDocTreeDefinition(def)
	if nil != err {
		return "", err
	}
	if maxTemplateDocTreeDocs < len(flattenTemplateDocTreeNodes0(collector.nodes))+len(flattenTemplateDocTreeNodes0(nodes)) {
		return "", fmt.Errorf("createDocTree exceeds the maximum document count of %d", maxTemplateDocTreeDocs)
	}
	collector.bindNodes(nodes, collector.rootID, collector.rootPath, collector.rootHPath)
	collector.nodes = append(collector.nodes, nodes...)
	return "", nil
}

func (collector *templateDocTreeCollector) bindNodes(nodes []*TemplateDocTreeNode, parentID, parentPath, parentHPath string) {
	for _, node := range nodes {
		node.ParentID = parentID
		node.path = strings.TrimSuffix(parentPath, ".sy") + "/" + node.ID + ".sy"
		node.HPath = path.Join(parentHPath, node.Title)

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Use the editor's manual template insert (insert template via the editor UI) so the kernel enables allowCreation.
  2. In tests, construct the collector with enabled=true and allowCreation=true (as the editor-insert path does).
  3. If you only need the parsed structure, call parseTemplateDocTreeDefinition directly instead of create().

Example fix

// before (test)
c := &templateDocTreeCollector{}
c.create(def) // enabled=false
// after
c := &templateDocTreeCollector{enabled: true, allowCreation: true, rootID: ..., rootPath: ..., rootHPath: ...}
c.create(def)
Defensive patterns

Strategy: try-catch

Validate before calling

// only call createDocTree in flows that go through manual editor template insert
const canCreate = renderMode === "editorInsert";

Try / catch

try {
  collector.create(def);
} catch (e) {
  if (String(e).includes("only available when manually inserting")) {
    // fall back to preview-only rendering or re-run via editor insert
  }
}

Prevention

When it happens

Trigger: Invoking the template's createDocTree function during template preview (TemplateRenderModePreview), content rendering, or from a code path where the collector was constructed with allowCreation=false — e.g. calling the collector directly in tests or from non-editor-insert render flows.

Common situations: Developers testing a template that calls createDocTree and running it through the preview path; plugin/integration code reusing the render pipeline to execute templates; automated tests calling create() without simulating an editor insert.

Related errors


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