cloudreve/cloudreve · error
failed to read state file: %w
Error message
failed to read state file: %w
What it means
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.
Source
Thrown at application/migrator/migrator.go:168
m.v4client = v4client
return m, nil
}
// saveState persists migration state to file
func (m *Migrator) saveState() error {
data, err := json.Marshal(m.state)
if err != nil {
return fmt.Errorf("failed to marshal state: %w", err)
}
return os.WriteFile(m.statePath, data, 0644)
}
// loadState reads migration state from file
func (m *Migrator) loadState() error {
data, err := os.ReadFile(m.statePath)
if err != nil {
return fmt.Errorf("failed to read state file: %w", err)
}
return json.Unmarshal(data, m.state)
}
// updateStep updates current step and persists state
func (m *Migrator) updateStep(step int) error {
m.state.Step = step
return m.saveState()
}
func (m *Migrator) Migrate() error {
// Continue from the current step
if m.state.Step <= StepSchema {
m.l.Info("Creating basic v4 table schema...")
if err := m.v4client.Schema.Create(context.Background()); err != nil {
return fmt.Errorf("failed creating schema resources: %w", err)
}View on GitHub (pinned to 20c95ad73f)
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.
Defensive patterns
Strategy: validation
Validate before calling
// Prove the state file is readable by the current user before starting.
func stateReadable(path string) error {
f, err := os.OpenFile(path, os.O_RDONLY, 0)
if err != nil {
return fmt.Errorf("state file not readable: %w", err)
}
return f.Close()
} Type guard
func isPathPermError(err error) bool {
var pe *fs.PathError
return errors.As(err, &pe) && errors.Is(pe.Err, fs.ErrPermission)
} Try / catch
data, err := os.ReadFile(m.statePath)
if err != nil {
if isPathPermError(err) {
// fix ownership/permissions of the config dir, then retry unchanged
}
return fmt.Errorf("failed to read state file: %w", err)
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Switching the service user between runs; container restart with a different UID; cleanup/rotation scripts sweeping the config directory during a migration.
Related errors
- failed to update step: %w
- failed to load migration state: %w
- failed creating schema resources: %w
- failed to create file %q: %s, skipping...
- failed to open avatar file: %w
AI-assisted analysis of cloudreve/cloudreve@20c95ad73f (2026-08-16).
Data as JSON: /api/errors/1efbe857f9ebc426.
Report an issue: GitHub.