siyuan-note/siyuan · error

key must be a template field

Error message

key must be a template field

What it means

The set-attribute-view-template entry point looks up the target key and asserts that its type is exactly av.KeyTypeTemplate before delegating to updateAttributeViewColTemplate. Updating the template of a non-template column is rejected with this fixed message.

Solutions

  1. Verify key.Type === "template" for the keyID before calling
  2. Pass the key ID of the template column you intend to edit
  3. Convert the column to a template type first if template behavior is needed

Example fix

// before
setAttrViewTemplate(avID, textFieldID, "=NOW()") // textFieldID is type "text"
// after
const key = attrView.keys.find(k => k.type === "template");
setAttrViewTemplate(avID, key.id, "=NOW()")
Defensive patterns

Strategy: validation

Validate before calling

const key = (await getAttributeView(avID)).keys.find(k => k.id === keyID);
if (key && key.type !== "template") throw new Error(`key ${keyID} is type ${key.type}, not template`);

Type guard

const isTemplateKey = (k: {type: string}): k is {type: "template"} => k.type === "template";

Try / catch

try { await setAttrViewTemplate(avID, keyID, tpl); } catch (e) { if (String(e).includes("key must be a template field")) { console.warn("wrong column type for template update"); } else throw e; }

Prevention

When it happens

Trigger: Calling the set template API with a keyID that identifies a text/number/select or other non-template field.

Common situations: Using a stale field ID after the column type changed or the column was recreated; pointing the update at the wrong attribute view's key ID.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/1d99ab9375c9d422. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/attribute_view.go:7613

	}

	regenAttrViewGroups(attrView)
	err = av.SaveAttributeView(attrView)
	return
}

// SetAttributeViewKeyTemplate 设置模板字段公式,复用字段模板保存和分组更新逻辑。
func SetAttributeViewKeyTemplate(avID, keyID, templateContent string) (err error) {
	attrView, err := av.ParseAttributeView(avID)
	if nil != err {
		return err
	}
	key, err := attrView.GetKey(keyID)
	if nil != err {
		return err
	}
	if av.KeyTypeTemplate != key.Type {
		return errors.New("key must be a template field")
	}
	return updateAttributeViewColTemplate(&Operation{
		AvID: avID, ID: keyID, Typ: string(av.KeyTypeTemplate), Data: templateContent,
	})
}

func (tx *Transaction) doUpdateAttrViewColNumberFormat(operation *Operation) (ret *TxErr) {
	err := updateAttributeViewColNumberFormat(operation)
	if err != nil {
		return &TxErr{code: TxErrHandleAttributeView, id: operation.AvID, msg: err.Error()}
	}
	return
}

func updateAttributeViewColNumberFormat(operation *Operation) (err error) {
	attrView, err := av.ParseAttributeView(operation.AvID)
	if err != nil {
		return

View on GitHub (pinned to 9f775e8a12)