siyuan-note/siyuan · error

previous ID and next ID cannot both be specified

Error message

previous ID and next ID cannot both be specified

What it means

A new database block can be appended to a parent, or inserted relative to one sibling (before previousID or after nextID), but not positioned between two siblings simultaneously. Supplying both previousID and nextID is ambiguous, so the function rejects the call.

Source

Thrown at kernel/model/attribute_view_create.go:55

	Icon string `json:"icon,omitempty"`
}

// AttributeViewCreateResult 描述创建数据库后可供调用方继续操作的标识和数据。
type AttributeViewCreateResult struct {
	BlockID       string
	AvID          string
	ViewID        string
	AttributeView *av.AttributeView
}

// CreateAttributeViewDatabase 创建数据库块和对应属性视图,并按照 keySpecs 的顺序初始化字段。
func CreateAttributeViewDatabase(parentID, previousID, nextID, name, primaryKeyName string, layout av.LayoutType,
	keySpecs []*AttributeViewCreateKey) (ret *AttributeViewCreateResult, err error) {
	if "" == parentID {
		return nil, errors.New("parent ID is required")
	}
	if "" != previousID && "" != nextID {
		return nil, errors.New("previous ID and next ID cannot both be specified")
	}
	if "" == previousID && "" == nextID {
		if err = treenode.CheckContainerParent(parentID); nil != err {
			return nil, err
		}
	}
	if "" == layout {
		layout = av.LayoutTypeTable
	}
	switch layout {
	case av.LayoutTypeTable, av.LayoutTypeGallery, av.LayoutTypeKanban:
	default:
		return nil, av.ErrWrongLayoutType
	}

	preparedKeys := make([]*av.Key, 0, len(keySpecs))
	for _, spec := range keySpecs {
		if nil == spec || "" == strings.TrimSpace(spec.Name) || "" == strings.TrimSpace(spec.Type) {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Pass only one of previousID or nextID, leaving the other as ""
  2. If you truly need to insert between two blocks, pass the left neighbor as previousID and empty nextID (or the right neighbor as nextID)
  3. Add caller-side logic that clears the opposite field when one anchor is chosen

Example fix

// before
ret, err := model.CreateAttributeViewDatabase(parentID, prevID, nextID, name, pk, layout, keys)
// after
if prevID != "" {
    nextID = "" // only one sibling anchor is allowed
}
ret, err := model.CreateAttributeViewDatabase(parentID, prevID, nextID, name, pk, layout, keys)
Defensive patterns

Strategy: validation

Validate before calling

if previousID != "" && nextID != "" {
    return errors.New("specify only one of previousID or nextID")
}

Prevention

When it happens

Trigger: Calling CreateAttributeViewDatabase with both previousID and nextID set to non-empty values.

Common situations: A caller that forwards UI selection state (which may contain both anchor directions) directly into the API; code that builds insertion options from a struct with optional fields but forgets to clear the unused sibling.

Related errors


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