siyuan-note/siyuan · error

email value is missing

Error message

email value is missing

What it means

When the key type is KeyTypeEmail, the value must carry a non-nil Value.Email object; otherwise normalization fails with 'email value is missing'. The function rejects the value so invalid template data never reaches the attribute view.

Solutions

  1. Add the email object: {"email":{"content":"user@example.com"}}
  2. Use the text type if the content is not a real email field
  3. Drop the value so pruning silently removes it
  4. Validate Value.Email != nil for every email-typed value before calling

Example fix

// before
{"type":"email"}
// after
{"type":"email","email":{"content":"user@example.com"}}
Defensive patterns

Strategy: validation

Validate before calling

if v.Type == av.KeyTypeEmail && v.Email == nil {
    return fmt.Errorf("email value requires an email object")
}

Type guard

func hasEmail(v *av.Value) bool { return v != nil && v.Type == av.KeyTypeEmail && v.Email != nil }

Prevention

When it happens

Trigger: A value passed through PruneInvalidNewItemTemplateFieldValues or normalizeNewItemTemplateFieldValues with KeyTypeEmail and Value.Email == nil (email sub-object omitted from the JSON).

Common situations: Copy-pasting a URL/text template value and switching the type to email without adding the email object; API consumers assuming the email content lives in Value.Text.

Related errors


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

Appendix: source

Thrown at kernel/av/new_item_template.go:393

		var selections []*ValueSelect
		for _, selection := range value.MSelect {
			if nil != selection && "" != strings.TrimSpace(selection.Content) {
				selections = append(selections, selection)
			}
		}
		if KeyTypeSelect == key.Type && 1 < len(selections) {
			selections = selections[:1]
		}
		value.MSelect = selections
		value.Text, value.Number, value.Date, value.URL, value.Email, value.Phone, value.MAsset, value.Checkbox, value.Relation = nil, nil, nil, nil, nil, nil, nil, nil, nil
	case KeyTypeURL:
		if nil == value.URL {
			return nil, errors.New("URL value is missing")
		}
		value.Text, value.Number, value.Date, value.MSelect, value.Email, value.Phone, value.MAsset, value.Checkbox, value.Relation = nil, nil, nil, nil, nil, nil, nil, nil, nil
	case KeyTypeEmail:
		if nil == value.Email {
			return nil, errors.New("email value is missing")
		}
		value.Text, value.Number, value.Date, value.MSelect, value.URL, value.Phone, value.MAsset, value.Checkbox, value.Relation = nil, nil, nil, nil, nil, nil, nil, nil, nil
	case KeyTypePhone:
		if nil == value.Phone {
			return nil, errors.New("phone value is missing")
		}
		value.Text, value.Number, value.Date, value.MSelect, value.URL, value.Email, value.MAsset, value.Checkbox, value.Relation = nil, nil, nil, nil, nil, nil, nil, nil, nil
	case KeyTypeMAsset:
		var assets []*ValueAsset
		for _, asset := range value.MAsset {
			if nil != asset && "" != strings.TrimSpace(asset.Content) {
				if AssetTypeFile != asset.Type && AssetTypeImage != asset.Type {
					return nil, fmt.Errorf("invalid asset type [%s]", asset.Type)
				}
				assets = append(assets, asset)
			}
		}
		value.MAsset = assets

View on GitHub (pinned to 9f775e8a12)