{"record":{"id":"d1d2bab4eb6a46f2","repo":"siyuan-note/siyuan","slug":"attribute-view-history-context-is-ambiguous-s","errorCode":null,"errorMessage":"attribute view history context is ambiguous [%s]","messagePattern":"attribute view history context is ambiguous \\[(.+?)\\]","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view_render.go","lineNumber":1103,"sourceCode":"\t\tif gulu.File.IsExist(filepath.Join(historyDir, \"storage\", \"av\", avID+\".json\")) {\n\t\t\tboxIDs = append(boxIDs, \"\")\n\t\t}\n\t\tentries, _ := os.ReadDir(historyDir)\n\t\tfor _, entry := range entries {\n\t\t\tif !entry.IsDir() || !ast.IsNodeIDPattern(entry.Name()) {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tcandidate := filepath.Join(historyDir, entry.Name(), \"storage\", \"av\", avID+\".json\")\n\t\t\tif gulu.File.IsExist(candidate) {\n\t\t\t\tboxIDs = append(boxIDs, entry.Name())\n\t\t\t}\n\t\t}\n\t}\n\tif len(boxIDs) == 0 {\n\t\treturn \"\", av.ErrAttributeViewNotFound\n\t}\n\tif len(boxIDs) != 1 {\n\t\treturn \"\", fmt.Errorf(\"attribute view history context is ambiguous [%s]\", avID)\n\t}\n\tif IsEncryptedBox(boxIDs[0]) {\n\t\treturn boxIDs[0], nil\n\t}\n\treturn \"\", nil\n}\n\nfunc RenderRepoSnapshotAttributeView(indexID, avID, viewID, carrierViewID string) (viewable av.Viewable, attrView *av.AttributeView, err error) {\n\tif !ast.IsNodeIDPattern(avID) {\n\t\terr = ErrInvalidID\n\t\treturn\n\t}\n\n\trepo, err := newRepository()\n\tif err != nil {\n\t\treturn\n\t}\n","sourceCodeStart":1085,"sourceCodeEnd":1121,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/attribute_view_render.go#L1085-L1121","documentation":"Thrown by ResolveHistoryAttributeViewBoxID when resolving which encrypted notebook owns a historical attribute view. After globbing history directories whose name starts with the formatted 'created' timestamp and scanning each for a file storage/av/<avID>.json (both at the global level and inside each notebook subdirectory), more than one distinct source context matched. The resolver requires exactly one match so it can decide whether an encrypted box key is needed.","triggerScenarios":"Calling the history-attribute-view resolve/render flow (API renderHistoryAttributeView) with an avID that exists in more than one place within the matching history snapshot: simultaneously in global storage/av/ and inside a notebook <boxID>/storage/av/, or inside two different notebook subdirectories. Duplicate or mirrored AV files in the history tree make the owner ambiguous.","commonSituations":"A synced or imported workspace where an attribute view was copied between the global storage and a notebook, or where two notebooks each hold a file with the same avID. History snapshots taken right after such a copy produce multiple candidates. AV IDs are expected globally unique; a collision usually indicates duplicated data.","solutions":["Inspect the matched history directory (named <created>-*) and delete or deduplicate the stray storage/av/<avID>.json so only one owner remains.","If the duplicate is legitimate (e.g. two notebooks legitimately referencing one AV), restructure so the AV lives in exactly one storage location and the other references point to it.","Regenerate the history snapshot after deduplication so the resolve path finds a single candidate."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before rendering, ensure the AV resolves to exactly one history source.\nboxID, err := model.ResolveHistoryAttributeViewBoxID(avID, created)\nif err != nil {\n    // surface 'ambiguous' / 'not found' to the user; do not call render\n    return err\n}\n// boxID is \"\" for global plaintext or a boxID for encrypted; safe to proceed","typeGuard":null,"tryCatchPattern":"if err := model.ResolveHistoryAttributeViewBoxID(avID, created); err != nil {\n    if strings.Contains(err.Error(), \"ambiguous\") {\n        // prompt user to deduplicate the AV across notebooks/global storage\n    }\n    return err\n}","preventionTips":["Keep each attribute view in exactly one storage location (global or a single notebook) to avoid ambiguous resolution.","After sync/import, verify no AV ID appears under two paths in the same history snapshot.","Treat an 'ambiguous' result as a data-integrity signal and dedupe before retrying."],"tags":["attribute-view","history","encryption","ambiguous-state"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}