siyuan-note/siyuan · error

attribute view source is required

Error message

attribute view source is required

What it means

SaveAttributeViewIfUnchanged performs a compare-and-swap style save: it only writes if the global database still matches the `original` bytes captured by the caller. Passing nil for `original` means there is no baseline to compare against, so the API refuses the call — callers wanting unconditional saves must use SaveAttributeView instead.

Solutions

  1. Read the current AV data and pass those bytes as `original` before calling SaveAttributeViewIfUnchanged
  2. If an unconditional save is intended, call SaveAttributeView(av) instead
  3. Restructure the flow so the conditional-save path is only reached when a real snapshot was captured

Example fix

// before
av.SaveAttributeViewIfUnchanged(attrView, nil)
// after
original, err := av.GetAttributeViewData(av.ID)
if err != nil { return err }
err = av.SaveAttributeViewIfUnchanged(attrView, original)
Defensive patterns

Strategy: validation

Validate before calling

if original == nil {
  return errors.New("SaveAttributeViewIfUnchanged requires a non-nil original snapshot; use SaveAttributeView for unconditional saves")
}

Try / catch

if err := avlib.SaveAttributeViewIfUnchanged(attrView, original); err != nil {
  if strings.Contains(err.Error(), "source is required") {
    return avlib.SaveAttributeView(attrView) // fall back to unconditional
  }
  return err
}

Prevention

When it happens

Trigger: Calling SaveAttributeViewIfUnchanged(av, nil); a code path that conditionally captured the original bytes (e.g. only when the file existed) and then proceeds to the conditional save even when capture failed; refactor that swapped SaveAttributeView for SaveAttributeViewIfUnchanged without threading the original snapshot.

Common situations: Plugin/automation code doing optimistic concurrency saves that skipped the initial read; first-creation flows where no original data exists; merge scripts that pass through a nil baseline.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at kernel/av/av.go:950

		}
	}
	if nil == err {
		err = CheckSpec(ret)
	}
	if nil == err {
		err = ret.NormalizeRichText()
	}
	return
}

func SaveAttributeView(av *AttributeView) (err error) {
	return saveAttributeView(av, nil)
}

// SaveAttributeViewIfUnchanged 仅在全局数据库仍与扫描源一致时原子保存。
func SaveAttributeViewIfUnchanged(av *AttributeView, original []byte) error {
	if original == nil {
		return errors.New("attribute view source is required")
	}
	return saveAttributeView(av, original)
}

func saveAttributeView(av *AttributeView, original []byte) (err error) {
	if !ast.IsNodeIDPattern(av.ID) {
		err = ErrInvalidAttributeViewID
		logging.LogErrorf("save attribute view failed: %s", err)
		return
	}
	defer func() {
		if nil == err {
			av.ResetCardCoverPositionChanges()
		}
	}()

	if err = av.NormalizeRichText(); nil != err {
		logging.LogErrorf("normalize attribute view [%s] rich text failed: %s", av.ID, err)

View on GitHub (pinned to 9f775e8a12)