amir20/dozzle · error

failed to create data directory

Error message

failed to create data directory: %w

What it means

After applying notification config changes in-memory, the agent CLI handler persists them under ./data, creating the directory with os.MkdirAll if needed. Failure to create ./data (permissions, read-only filesystem, path is a file) is wrapped with this message.

Solutions

  1. Check the wrapped syscall error (EACCES/EROFS/EEXIST etc.) to identify the cause
  2. Ensure ./data is a writable directory: mkdir -p data and chown to the process user
  3. Mount a writable volume for the data directory when running in a container
  4. Remove any regular file occupying the ./data path

Example fix

// before
# container run with read-only fs, no data volume
// after
# docker run -v dozzle-data:/data ... (writable volume for ./data)
Defensive patterns

Strategy: try-catch

Validate before calling

if fi, err := os.Stat("./data"); err == nil && !fi.IsDir() {
    return fmt.Errorf("./data exists but is not a directory")
}

Try / catch

if err := h.manager.HandleNotificationConfig(subs, dispatchers); err != nil {
    if errors.Is(err, fs.ErrPermission) { /* fix ownership / mount a volume */ }
    return err
}

Prevention

When it happens

Trigger: os.MkdirAll("./data", 0755) returning an error: parent directory not writable, a regular file named ./data exists, read-only container filesystem, or disk full.

Common situations: Running the agent as non-root in a container with a read-only rootfs and no volume mounted at /data; ./data pre-created by another process as a file; SELinux/AppArmor denying writes.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07). Data as JSON: /api/errors/41e2c8b0e3a6a21b. Report an issue: GitHub.

Appendix: source

Thrown at internal/support/cli/agent_command.go:58

}

func (h *persistingNotificationHandler) setCloudConfig(cc *notification.CloudConfig) {
	h.cloudConfig.Store(cc)
}

func (h *persistingNotificationHandler) GetNotificationStats() []types.SubscriptionStats {
	return h.manager.GetNotificationStats()
}

func (h *persistingNotificationHandler) HandleNotificationConfig(subscriptions []types.SubscriptionConfig, dispatchers []types.DispatcherConfig) error {
	// Update the manager
	if err := h.manager.HandleNotificationConfig(subscriptions, dispatchers); err != nil {
		return err
	}

	// Save to disk
	if err := os.MkdirAll("./data", 0755); err != nil {
		return fmt.Errorf("failed to create data directory: %w", err)
	}

	file, err := os.Create(h.configPath)
	if err != nil {
		return fmt.Errorf("failed to create config file: %w", err)
	}
	defer file.Close()

	if err := h.manager.WriteConfig(file); err != nil {
		return fmt.Errorf("failed to save config: %w", err)
	}

	log.Debug().Str("path", h.configPath).Msg("Saved notification config to disk")
	return nil
}

// SetCloudStreamLogs applies the hub's log-streaming choice to this agent's own
// cloud client. The agent streams its logs to cloud itself rather than through

View on GitHub (pinned to d9463cbe21)