cloudreve/cloudreve · critical
failed to write config file: %w
Error message
failed to write config file: %w
What it means
Thrown by NewIniConfigProvider (pkg/conf/conf.go:46) when the freshly created config file was opened but f.WriteString(confContent) fails to write the rendered default template. The file handle is valid, so this is an I/O-time failure: disk full (ENOSPC), quota exceeded, device/FS-level write errors (NFS stale handle, disk detached), or the file was opened on a filesystem that went read-only. Startup aborts because the config was never persisted.
Source
Thrown at pkg/conf/conf.go:46
// NewIniConfigProvider initializes a new Ini config file provider. A default config file
// will be created if the given path does not exist.
func NewIniConfigProvider(configPath string, l logging.Logger) (ConfigProvider, error) {
if configPath == "" || !util.Exists(configPath) {
l.Info("Config file %q not found, creating a new one.", configPath)
// 创建初始配置文件
confContent := util.Replace(map[string]string{
"{SessionSecret}": util.RandStringRunesCrypto(64),
}, defaultConf)
f, err := util.CreatNestedFile(configPath)
if err != nil {
return nil, fmt.Errorf("failed to create config file: %w", err)
}
// 写入配置文件
_, err = f.WriteString(confContent)
if err != nil {
return nil, fmt.Errorf("failed to write config file: %w", err)
}
f.Close()
}
cfg, err := ini.Load(configPath, []byte(getOverrideConfFromEnv(l)))
if err != nil {
return nil, fmt.Errorf("failed to parse config file %q: %w", configPath, err)
}
provider := &iniConfigProvider{
database: *DatabaseConfig,
system: *SystemConfig,
ssl: *SSLConfig,
unix: *UnixConfig,
slave: *SlaveConfig,
redis: *RedisConfig,
cors: *CORSConfig,View on GitHub (pinned to 20c95ad73f)
Solutions
- Free space or raise the quota on the volume holding the config path (df -h to confirm)
- If the FS remounted read-only, check dmesg for disk errors, fix, and remount rw
- Move the config path to a reliably writable local volume
- For containers, increase ephemeral-storage limits or write config to a mounted volume
Example fix
# before $ ./cloudreve failed to write config file: write /cloudreve/conf.ini: no space left on device # after $ df -h /cloudreve $ docker system prune # or extend the volume $ ./cloudreve
Defensive patterns
Strategy: validation
Validate before calling
// free-space preflight for the config volume
func checkDiskSpace(dir string, need uint64) error {
var st syscall.Statfs_t
if err := syscall.Statfs(dir, &st); err != nil {
return err
}
if uint64(st.Bavail)*uint64(st.Bsize) < need {
return fmt.Errorf("less than %d bytes free on %s", need, dir)
}
return nil
} Type guard
func isDiskFull(err error) bool {
return err != nil && (errors.Is(err, syscall.ENOSPC) || strings.Contains(err.Error(), "no space left on device"))
} Try / catch
provider, err := conf.NewIniConfigProvider(configPath, l)
if err != nil {
if isDiskFull(err) {
log.Fatalf("config volume is full; free space or extend the disk, then restart")
}
log.Fatalf("config write failed: %v", err)
} Prevention
- Monitor free space on the config volume and alert well before zero
- Keep config on a local reliable disk, not a flaky network mount
- Set container ephemeral-storage limits with headroom
- Watch dmesg for filesystem errors that force read-only remounts
When it happens
Trigger: First-run generation of the INI file on a full disk; writing across a network mount that drops mid-write; the underlying ext4 flipped to read-only after detecting errors; cgroup/FS quota exhaustion in containers.
Common situations: Small VPS or container with a full volume; config dir on NFS/SMB with intermittent availability; container ephemeral storage limit reached; hardware disk failing and kernel remounts ro.
Related errors
- failed to create config file: %w
- failed to create file %q: %s, skipping...
- failed to parse config file %q: %w
- failed to parse config section %q: %w
- failed to delete socket file %q: %w
AI-assisted analysis of cloudreve/cloudreve@20c95ad73f (2026-08-16).
Data as JSON: /api/errors/d3b0ffe354add716.
Report an issue: GitHub.