siyuan-note/siyuan · error

attribute view history context is ambiguous

Error message

attribute view history context is ambiguous [%s]

What it means

ResolveHistoryAttributeViewBoxID globs the history directory for entries matching the timestamp prefix and collects the notebook (box) IDs that contain the attribute view. Uniqueness is required: if the avID is found under more than one box in the same history window, the context is ambiguous and this error is returned.

Solutions

  1. Identify which history entry/box is the intended one and remove or ignore the duplicate
  2. Deduplicate the attribute view file across notebooks in the history window
  3. Supply explicit notebook context upstream so resolution does not have to guess

Example fix

// before
boxID, err := model.ResolveHistoryAttributeViewBoxID(avID, created) // ambiguous
// after
// narrow the history window or deduplicate boxes first
boxID, err := model.ResolveHistoryAttributeViewBoxID(avID, createdAtExactSnapshot)
Defensive patterns

Strategy: try-catch

Validate before calling

boxIDs := collectHistoryBoxIDs(avID, createdPrefix)
if len(boxIDs) > 1 { return ErrAmbiguous }

Try / catch

boxID, err := model.ResolveHistoryAttributeViewBoxID(avID, created)
if err != nil && strings.Contains(err.Error(), "history context is ambiguous") {
    return letUserSelectSourceNotebook(avID)
}

Prevention

When it happens

Trigger: The same attribute view ID appears under multiple notebooks within history snapshots at the given created timestamp — typically after documents were copied/moved between notebooks and both histories captured it.

Common situations: Copying a document with a database between notebooks then browsing history; sync conflicts duplicating av files across boxes; restored backups retaining duplicates.

Related errors


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

Appendix: source

Thrown at kernel/model/attribute_view_render.go:1258

		if gulu.File.IsExist(filepath.Join(historyDir, "storage", "av", avID+".json")) {
			boxIDs = append(boxIDs, "")
		}
		entries, _ := os.ReadDir(historyDir)
		for _, entry := range entries {
			if !entry.IsDir() || !ast.IsNodeIDPattern(entry.Name()) {
				continue
			}
			candidate := filepath.Join(historyDir, entry.Name(), "storage", "av", avID+".json")
			if gulu.File.IsExist(candidate) {
				boxIDs = append(boxIDs, entry.Name())
			}
		}
	}
	if len(boxIDs) == 0 {
		return "", av.ErrAttributeViewNotFound
	}
	if len(boxIDs) != 1 {
		return "", fmt.Errorf("attribute view history context is ambiguous [%s]", avID)
	}
	if IsEncryptedBox(boxIDs[0]) {
		return boxIDs[0], nil
	}
	return "", nil
}

func loadHistoryWorkspacePalette(historyDir string) (
	ret []*av.AttributeViewCustomColor, order []string, found bool,
) {
	path := filepath.Join(historyDir, "storage", "inline-styles.json")
	if !gulu.File.IsExist(path) {
		return nil, nil, false
	}
	data, err := os.ReadFile(path)
	if nil != err {
		logging.LogWarnf("read historical inline styles failed: %s", err)
		return nil, nil, false

View on GitHub (pinned to 9f775e8a12)