Billionmail/BillionMail · error

create thumbnail dir: %w

Error message

create thumbnail dir: %w

What it means

GenerateThumbnail creates the parent directory of cfg.OutputPath via os.MkdirAll before invoking ImageMagick. If directory creation fails (permissions, read-only fs, path is a file), the OS error is wrapped with 'create thumbnail dir: %w'.

Source

Thrown at core/internal/service/video_gen/thumbnail.go:58

	}
	h := cfg.Height
	if h == 0 {
		h = defaultThumbHeight
	}

	return []string{
		cfg.InputPath,
		"-resize", fmt.Sprintf("%dx%d!", w, h),
		"-quality", "90",
		cfg.OutputPath,
	}
}

// GenerateThumbnail creates a thumbnail from a screenshot using ImageMagick.
// Requires: magick (ImageMagick) installed.
func GenerateThumbnail(ctx context.Context, cfg ThumbnailConfig) (string, error) {
	if err := os.MkdirAll(filepath.Dir(cfg.OutputPath), 0755); err != nil {
		return "", fmt.Errorf("create thumbnail dir: %w", err)
	}

	args := BuildThumbnailArgs(cfg)
	cmd := exec.CommandContext(ctx, "magick", args...)
	out, err := cmd.CombinedOutput()
	if err != nil {
		return "", fmt.Errorf("imagemagick thumbnail failed: %w\noutput: %s", err, string(out))
	}

	return cfg.OutputPath, nil
}

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Inspect the wrapped OS error for the exact filesystem cause
  2. Ensure the thumbnail output directory exists and is writable by the process user
  3. Mount a writable volume for output paths in containers
  4. Verify OutputPath is constructed correctly (non-empty base dir, directory not a file)

Example fix

// before
if err := os.MkdirAll(filepath.Dir(cfg.OutputPath), 0755); err != nil {
	return "", fmt.Errorf("create thumbnail dir: %w", err)
}
// after
outDir := filepath.Dir(cfg.OutputPath)
if info, err := os.Stat(outDir); err == nil && !info.IsDir() {
	return "", fmt.Errorf("thumbnail output path %q is a file, not a directory", outDir)
}
if err := os.MkdirAll(outDir, 0755); err != nil {
	return "", fmt.Errorf("create thumbnail dir: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

outDir := filepath.Dir(cfg.OutputPath)
if outDir == "." || outDir == "" {
	return fmt.Errorf("thumbnail output path has no directory component")
}
if info, err := os.Stat(outDir); err == nil && !info.IsDir() {
	return fmt.Errorf("%s is a file", outDir)
}

Try / catch

path, err := GenerateThumbnail(ctx, cfg)
if err != nil && strings.HasPrefix(err.Error(), "create thumbnail dir:") {
	var perr *fs.PathError
	if errors.As(err, &perr) && errors.Is(perr.Err, fs.ErrPermission) {
		return fmt.Errorf("cannot write thumbnails to %s: check volume mount/permissions", filepath.Dir(cfg.OutputPath))
	}
}

Prevention

When it happens

Trigger: os.MkdirAll(filepath.Dir(cfg.OutputPath), 0755) fails: the parent of OutputPath is unwritable, already exists as a file, disk is full, or an invalid path segment is supplied.

Common situations: Same writable-volume issues as screenshot output in Docker; OutputPath built by joining a bad/empty base dir so Dir() resolves to an unwritable location; non-root process user lacking permissions.

Related errors


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/b003a84c3bedc459. Report an issue: GitHub.