siyuan-note/siyuan · error

database history has no primary field

Error message

database history has no primary field

What it means

readBoundAttributeViewHistory validates a historical snapshot of an attribute view (database) before it is backed up or merged back during document history restore/rollback. The snapshot must contain a primary (block-type) key field, retrieved via GetBlockKeyValues(); without it, no bound block entries can be identified or restored. The kernel throws this error to fail fast on a structurally incomplete or corrupted database history file rather than silently performing a partial restore.

Solutions

  1. Delete the offending snapshot under <historyDir>/<boxID>/storage/av/<avID>.json (or pick a different history version) so the restore skips the corrupt snapshot, then retry the rollback
  2. Verify the snapshot JSON contains a KeyValues entry whose Key.Type is "block"; if it was hand-edited, restore the primary field
  3. Check whether the database itself still has its primary key in the live workspace; if only the history is malformed, regenerate history by re-deleting after fixing the database
  4. Report/upgrade if produced by an older version — old history formats may lack the block key; use a history taken by the current version
Defensive patterns

Strategy: validation

Validate before calling

// Go: before relying on a history snapshot, check it has a primary field
func hasPrimaryField(data []byte) error {
    view, err := av.ParseAttributeViewData(avID, data)
    if err != nil { return err }
    if view.GetBlockKeyValues() == nil {
        return errors.New("snapshot has no primary (block) field")
    }
    return nil
}

Type guard

if view.GetBlockKeyValues() == nil {
    // handle missing primary field before use
    return ErrNoPrimaryField
}

Try / catch

view, err := readBoundAttributeViewHistory(file, boxID, avID)
if err != nil {
    if strings.Contains(err.Error(), "no primary field") {
        // skip this snapshot / pick another history version
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: RollbackDocHistory, restoreEmbeddedAttributeViewHistory, or backupBoundAttributeViewHistory reads a historical attribute-view JSON (storage/av/<avID>.json snapshot) whose KeyValues contain no KeyTypeBlock field — e.g. a hand-edited, truncated, or old-format history file, or a snapshot of a database whose block/primary key was deleted before deletion backup.

Common situations: Restoring a document whose database history snapshot predates schema changes or was produced by an older SiYuan version; corrupted or partially written history files after a crash; manually copying history files between workspaces or notebooks (encrypted vs plaintext mismatch handled separately); databases converted to detached-item-only layouts.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at kernel/model/attribute_view_block_history.go:56

	view, err := av.ParseAttributeViewData(avID, data)
	if err != nil {
		return nil, err
	}
	if view.ID != avID {
		return nil, errors.New("database history ID does not match its filename")
	}
	for _, kv := range view.KeyValues {
		if kv == nil || kv.Key == nil {
			return nil, errors.New("database history contains an invalid field")
		}
		for _, value := range kv.Values {
			if value == nil {
				return nil, errors.New("database history contains an invalid value")
			}
		}
	}
	if view.GetBlockKeyValues() == nil {
		return nil, errors.New("database history has no primary field")
	}
	for _, layout := range view.Views {
		if layout == nil {
			return nil, errors.New("database history contains an invalid view")
		}
		for _, group := range layout.Groups {
			if group == nil {
				return nil, errors.New("database history contains an invalid group")
			}
		}
	}
	return view, nil
}

// 内嵌数据库也先认证历史,并与绑定条目恢复一起纳入失败回滚。
func (tx *Transaction) restoreEmbeddedAttributeViewHistory(filename, boxID, avID string) error {
	historical, err := readBoundAttributeViewHistory(filename, boxID, avID)
	if err != nil {

View on GitHub (pinned to 9f775e8a12)