{"record":{"id":"4419d2d204677748","repo":"siyuan-note/siyuan","slug":"unmarshal-master-password-migration-failed-w","errorCode":null,"errorMessage":"unmarshal master password migration failed: %w","messagePattern":"unmarshal master password migration failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/crypto.go","lineNumber":566,"sourceCode":"\nfunc readMasterPasswordMigration() (*masterPasswordMigration, error) {\n\tmasterPasswordMigrationMu.Lock()\n\tdefer masterPasswordMigrationMu.Unlock()\n\treturn readMasterPasswordMigrationUnlocked()\n}\n\nfunc readMasterPasswordMigrationUnlocked() (*masterPasswordMigration, error) {\n\tp := masterPasswordMigrationPath()\n\tif !filelock.IsExist(p) {\n\t\treturn nil, nil\n\t}\n\tdata, err := filelock.ReadFile(p)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read master password migration failed: %w\", err)\n\t}\n\tvar m masterPasswordMigration\n\tif err = gulu.JSON.UnmarshalJSON(data, &m); err != nil {\n\t\treturn nil, fmt.Errorf(\"unmarshal master password migration failed: %w\", err)\n\t}\n\treturn &m, nil\n}\n\nfunc removeMasterPasswordMigration() {\n\tmasterPasswordMigrationMu.Lock()\n\tdefer masterPasswordMigrationMu.Unlock()\n\tremoveMasterPasswordMigrationUnlocked()\n}\n\nfunc removeMasterPasswordMigrationUnlocked() {\n\tp := masterPasswordMigrationPath()\n\tif err := filelock.Remove(p); err != nil && !os.IsNotExist(err) {\n\t\tlogging.LogErrorf(\"remove master password migration failed: %s\", err)\n\t}\n}\n\nfunc removeMasterPasswordMigrationBox(boxID string) {","sourceCodeStart":548,"sourceCodeEnd":584,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/crypto.go#L548-L584","documentation":"The migration file was read successfully but gulu.JSON.UnmarshalJSON could not decode it into masterPasswordMigration. This means the file content is not valid JSON or does not match the expected schema, and the kernel refuses to guess at partially valid migration state.","triggerScenarios":"readMasterPasswordMigrationUnlocked parses the file bytes and UnmarshalJSON returns an error — empty file, truncated write from a previous crash, hand-edited JSON, or a file written by an incompatible schema.","commonSituations":"A crash or power loss during a previous write left a partial JSON file, manual editing broke the structure, or restoring a migration file from a different SiYuan version with a different schema.","solutions":["Inspect the file content and fix or remove the malformed migration JSON","Delete the corrupt file and re-run the master password migration from a clean state","Restore the migration file from a known-good backup of the workspace data directory","Check the wrapped unmarshal error message for the exact offset/syntax problem before editing"],"exampleFix":"// before: truncated file content\n{\"masterSalt\": \"abc\" // cut off\n// after: valid complete JSON or remove and re-migrate\n{\"masterSalt\":\"abc\",\"wrappedDek\":\"...\",\"unlocked\":true}\nm, err := readMasterPasswordMigration()","handlingStrategy":"fallback","validationCode":"var probe map[string]any\nif err := json.Unmarshal(raw, &probe); err != nil {\n    return fmt.Errorf(\"migration file corrupt: %w\", err)\n}\nfor _, k := range []string{\"masterSalt\", \"wrappedDek\"} {\n    if _, ok := probe[k]; !ok {\n        return fmt.Errorf(\"migration file missing key %q\", k)\n    }\n}","typeGuard":null,"tryCatchPattern":"m, err := readMasterPasswordMigration()\nif err != nil {\n    // fall back: quarantine the corrupt file and re-run migration\n    os.Rename(masterPasswordMigrationPath(), masterPasswordMigrationPath()+\".corrupt\")\n    return fmt.Errorf(\"migration state unreadable, re-run migration: %w\", err)\n}","preventionTips":["Never hand-edit the migration JSON; delete and re-migrate instead","Back up the data directory before master password operations","Treat a truncated file after a crash as corrupt — restore from backup or re-run migration","Validate the file parses before upgrading kernels that change the migration schema"],"tags":["go","json","parsing","migration"],"backgroundTag":"json-unmarshal-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}