siyuan-note/siyuan · error

relation value is missing

Error message

relation value is missing

What it means

For KeyTypeRelation values, normalizeNewItemTemplateValue requires a non-nil Value.Relation object; otherwise it fails with 'relation value is missing'. Relation template values must identify the related blocks via Relation.BlockIDs, which the nil object cannot.

Solutions

  1. Populate the Relation object with the related block IDs
  2. Use an empty Relation {"relation":{"blockIDs":[]}} if no blocks are related yet
  3. Change the value type if no relation semantics are needed
  4. Remove the invalid value prior to pruning

Example fix

// before
{"type":"relation"}
// after
{"type":"relation","relation":{"blockIDs":["20240101120000-abcdef"]}}
Defensive patterns

Strategy: validation

Validate before calling

if v.Type == av.KeyTypeRelation && v.Relation == nil {
    return fmt.Errorf("relation value requires a relation object")
}

Type guard

func hasRelation(v *av.Value) bool { return v != nil && v.Type == av.KeyTypeRelation && v.Relation != nil }

Prevention

When it happens

Trigger: A value passed through PruneInvalidNewItemTemplateFieldValues or normalizeNewItemTemplateFieldValues with KeyTypeRelation and Value.Relation == nil (relation object missing from the template value).

Common situations: Templates created before a relation was linked (no BlockIDs yet); plugins generating relation rows without populating the Relation struct.

Related errors


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

Appendix: source

Thrown at kernel/av/new_item_template.go:420

		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
		value.Text, value.Number, value.Date, value.MSelect, value.URL, value.Email, value.Phone, value.Checkbox, value.Relation = nil, nil, nil, nil, nil, nil, nil, nil, nil
	case KeyTypeCheckbox:
		if nil == value.Checkbox {
			return nil, errors.New("checkbox value is missing")
		}
		value.Text, value.Number, value.Date, value.MSelect, value.URL, value.Email, value.Phone, value.MAsset, value.Relation = nil, nil, nil, nil, nil, nil, nil, nil, nil
	case KeyTypeRelation:
		if nil == value.Relation {
			return nil, errors.New("relation value is missing")
		}
		for _, blockID := range value.Relation.BlockIDs {
			if !ast.IsNodeIDPattern(blockID) {
				return nil, fmt.Errorf("invalid relation block ID [%s]", blockID)
			}
		}
		value.Text, value.Number, value.Date, value.MSelect, value.URL, value.Email, value.Phone, value.MAsset, value.Checkbox = nil, nil, nil, nil, nil, nil, nil, nil, nil
	default:
		return nil, fmt.Errorf("unsupported value type [%s]", key.Type)
	}
	value.Block, value.Template, value.Created, value.Updated, value.Rollup = nil, nil, nil, nil, nil
	value.ID = ""
	value.KeyID = ""
	value.BlockID = ""
	value.Type = key.Type
	value.IsDetached = false
	value.CreatedAt = 0
	value.UpdatedAt = 0

View on GitHub (pinned to 9f775e8a12)