siyuan-note/siyuan · error
unmarshal master password migration failed: %w
Error message
unmarshal master password migration failed: %w
What it means
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.
Source
Thrown at kernel/model/crypto.go:566
func readMasterPasswordMigration() (*masterPasswordMigration, error) {
masterPasswordMigrationMu.Lock()
defer masterPasswordMigrationMu.Unlock()
return readMasterPasswordMigrationUnlocked()
}
func readMasterPasswordMigrationUnlocked() (*masterPasswordMigration, error) {
p := masterPasswordMigrationPath()
if !filelock.IsExist(p) {
return nil, nil
}
data, err := filelock.ReadFile(p)
if err != nil {
return nil, fmt.Errorf("read master password migration failed: %w", err)
}
var m masterPasswordMigration
if err = gulu.JSON.UnmarshalJSON(data, &m); err != nil {
return nil, fmt.Errorf("unmarshal master password migration failed: %w", err)
}
return &m, nil
}
func removeMasterPasswordMigration() {
masterPasswordMigrationMu.Lock()
defer masterPasswordMigrationMu.Unlock()
removeMasterPasswordMigrationUnlocked()
}
func removeMasterPasswordMigrationUnlocked() {
p := masterPasswordMigrationPath()
if err := filelock.Remove(p); err != nil && !os.IsNotExist(err) {
logging.LogErrorf("remove master password migration failed: %s", err)
}
}
func removeMasterPasswordMigrationBox(boxID string) {View on GitHub (pinned to 8641553a1f)
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
Example fix
// before: truncated file content
{"masterSalt": "abc" // cut off
// after: valid complete JSON or remove and re-migrate
{"masterSalt":"abc","wrappedDek":"...","unlocked":true}
m, err := readMasterPasswordMigration() Defensive patterns
Strategy: fallback
Validate before calling
var probe map[string]any
if err := json.Unmarshal(raw, &probe); err != nil {
return fmt.Errorf("migration file corrupt: %w", err)
}
for _, k := range []string{"masterSalt", "wrappedDek"} {
if _, ok := probe[k]; !ok {
return fmt.Errorf("migration file missing key %q", k)
}
} Try / catch
m, err := readMasterPasswordMigration()
if err != nil {
// fall back: quarantine the corrupt file and re-run migration
os.Rename(masterPasswordMigrationPath(), masterPasswordMigrationPath()+".corrupt")
return fmt.Errorf("migration state unreadable, re-run migration: %w", err)
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- marshal master password migration failed: %w
- attribute view spec is too new
- master password migration is pending
- invalid session data
- decode session data failed: %w
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/4419d2d204677748.
Report an issue: GitHub.