siyuan-note/siyuan · error
source row [%s] not found in attribute view [%s]
Error message
source row [%s] not found in attribute view [%s]
What it means
Thrown by DuplicateAttributeViewRow when blockKeyValues.GetValue(srcRowID) returns nil, i.e. the row selected for duplication does not have a value in the primary (block) key column. The source row must exist in the AV before it can be copied.
Source
Thrown at kernel/model/attribute_view.go:2052
// DuplicateAttributeViewRow 创建源行的纯文本副本,复制除主键、Rollup、Created、Updated 外的所有字段值,
// 双向关联同步更新目标属性视图的反向关联列。新行 ID 由调用方(前端)生成并通过 newRowID 传入,
// 副本插入到 previousItemID(通常为最后选中的条目)之后。
func DuplicateAttributeViewRow(tx *Transaction, avID, previousItemID, srcRowID, newRowID string) (err error) {
attrView, err := av.ParseAttributeView(avID)
if err != nil {
logging.LogErrorf("parse attribute view [%s] failed: %s", avID, err)
return
}
blockKeyValues := attrView.GetBlockKeyValues()
if nil == blockKeyValues {
err = fmt.Errorf("attribute view [%s] has no block key", avID)
return
}
srcBlockVal := blockKeyValues.GetValue(srcRowID)
if nil == srcBlockVal {
err = fmt.Errorf("source row [%s] not found in attribute view [%s]", srcRowID, avID)
return
}
if "" == newRowID {
newRowID = ast.NewNodeID()
}
now := util.CurrentTimeMillis()
// 创建副本的主键值,强制为纯文本(非绑定块)
blockContent := ""
if nil != srcBlockVal.Block {
blockContent = srcBlockVal.Block.Content
}
newBlockVal := &av.Value{
ID: ast.NewNodeID(),
KeyID: blockKeyValues.Key.ID,
BlockID: newRowID,View on GitHub (pinned to 251596fc0d)
Solutions
- Confirm srcRowID exists in the AV's block key values before invoking DuplicateAttributeViewRow.
- Refresh the row list on the client when the AV is updated externally (sync, another window) and invalidate cached row IDs.
- Surface a user-facing 'row no longer exists' message instead of silently failing.
Example fix
// before
DuplicateAttributeViewRow(tx, avID, prevID, maybeDeletedRowID, newRowID)
// after
rows := attrView.GetBlockKeyValues()
if rows.GetValue(srcRowID) == nil {
return fmt.Errorf("source row %s no longer exists", srcRowID)
}
DuplicateAttributeViewRow(tx, avID, prevID, srcRowID, newRowID) Defensive patterns
Strategy: validation
Validate before calling
const blockVals = av.getBlockKeyValues()
const srcExists = blockVals && blockVals.values.some(v => v.blockID === srcRowID)
if (!srcExists) { /* source row is gone; do not call DuplicateAttributeViewRow */ } Try / catch
try { await duplicateRow(avID, prevID, srcRowID, newRowID) } catch (e) {
if (/source row .* not found/.test(String(e.message ?? e))) { refreshRows(avID) } else { throw e }
} Prevention
- Invalidate cached row IDs when the AV is modified externally.
- Confirm the source row exists immediately before invoking duplicate.
When it happens
Trigger: Passing a srcRowID that was already deleted, belongs to another AV, or was never committed; calling duplicate during a sync that has not yet pulled the row.
Common situations: Stale selection state in the frontend after a delete/sync; programmatic callers reusing a row ID cached from a previous session.
Related errors
- attribute view item [%s] not found
- invalid card aspect ratio preset [%v]
- invalid card aspect ratio [%v]
- at least one visible view is required
- view [%s] not found in attribute view [%s]
AI-assisted analysis of siyuan-note/siyuan@251596fc0d (2026-08-12).
Data as JSON: /api/errors/89707b7c9df575b3.
Report an issue: GitHub.