{"record":{"id":"1efbe857f9ebc426","repo":"cloudreve/cloudreve","slug":"failed-to-read-state-file-w","errorCode":null,"errorMessage":"failed to read state file: %w","messagePattern":"failed to read state file: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"application/migrator/migrator.go","lineNumber":168,"sourceCode":"\tm.v4client = v4client\n\treturn m, nil\n}\n\n// saveState persists migration state to file\nfunc (m *Migrator) saveState() error {\n\tdata, err := json.Marshal(m.state)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal state: %w\", err)\n\t}\n\n\treturn os.WriteFile(m.statePath, data, 0644)\n}\n\n// loadState reads migration state from file\nfunc (m *Migrator) loadState() error {\n\tdata, err := os.ReadFile(m.statePath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read state file: %w\", err)\n\t}\n\n\treturn json.Unmarshal(data, m.state)\n}\n\n// updateStep updates current step and persists state\nfunc (m *Migrator) updateStep(step int) error {\n\tm.state.Step = step\n\treturn m.saveState()\n}\n\nfunc (m *Migrator) Migrate() error {\n\t// Continue from the current step\n\tif m.state.Step <= StepSchema {\n\t\tm.l.Info(\"Creating basic v4 table schema...\")\n\t\tif err := m.v4client.Schema.Create(context.Background()); err != nil {\n\t\t\treturn fmt.Errorf(\"failed creating schema resources: %w\", err)\n\t\t}","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/cloudreve/cloudreve/blob/20c95ad73f3a8bcb72887fea91ff31ab24fa1011/application/migrator/migrator.go#L150-L186","documentation":"loadState calls os.ReadFile on migration_state.json and wraps the resulting *fs.PathError with this message. It only surfaces when util.Exists(m.statePath) reported true a moment earlier, so typical causes are a race (the file disappeared between check and read) or a permission failure (the file exists but the current user cannot read it). A path that is actually a directory also produces this error.","triggerScenarios":"Another process deletes or rotates the state file between the Exists check and the ReadFile; the file is owned by root while the migrator runs as an unprivileged user (typical Docker volume UID mismatch); migration_state.json path is occupied by a directory; SELinux/AppArmor denies the read.","commonSituations":"Switching the service user between runs; container restart with a different UID; cleanup/rotation scripts sweeping the config directory during a migration.","solutions":["Check ls -l <confDir>/migration_state.json for ownership and mode; the running user needs read access (at least 0400).","Fix ownership: chown the config directory and state file to the service user, or adjust the mount's UID/GID.","If the file is unexpected, move it away so the migration starts fresh (clean the v4 database first).","Re-run the migrator after the fix."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Prove the state file is readable by the current user before starting.\nfunc stateReadable(path string) error {\n\tf, err := os.OpenFile(path, os.O_RDONLY, 0)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"state file not readable: %w\", err)\n\t}\n\treturn f.Close()\n}","typeGuard":"func isPathPermError(err error) bool {\n\tvar pe *fs.PathError\n\treturn errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission)\n}","tryCatchPattern":"data, err := os.ReadFile(m.statePath)\nif err != nil {\n\tif isPathPermError(err) {\n\t\t// fix ownership/permissions of the config dir, then retry unchanged\n\t}\n\treturn fmt.Errorf(\"failed to read state file: %w\", err)\n}","preventionTips":["Run the migrator as the user that owns the config directory.","Mount Docker config volumes with matching UID/GID.","Keep cleanup/rotation scripts away from the config dir during migration."],"tags":["go","filesystem","cloudreve","migration","permissions","docker"],"backgroundTag":null,"analyzedSha":"20c95ad73f3a8bcb72887fea91ff31ab24fa1011","analyzedAt":"2026-08-16T01:42:55.403Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}