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
- Read the current AV data and pass those bytes as `original` before calling SaveAttributeViewIfUnchanged
- If an unconditional save is intended, call SaveAttributeView(av) instead
- 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
- Always capture the current AV data bytes before scheduling a conditional save
- Use SaveAttributeView when no baseline exists (e.g. first creation)
- Keep snapshot capture and conditional save in the same code path so nil cannot slip through
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
- attribute view content is unavailable
- attribute view rows changed; retry the drag
- clone attribute view
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)