Billionmail/BillionMail · error

scan maildirsize failed: %w

Error message

scan maildirsize failed: %w

What it means

readMaildirsize scans the maildirsize file line by line with bufio.Scanner. This error propagates any non-EOF I/O error returned by scanner.Err() after the scan loop, indicating the file could not be fully read rather than parsed.

Source

Thrown at core/internal/service/mail_boxes/update_used_space.go:232

		if lineNo == 1 {

			continue
		}

		sizeStr := parts[0]

		sizeStr = strings.TrimSuffix(sizeStr, "S")

		v, err := strconv.ParseInt(sizeStr, 10, 64)
		if err != nil {
			return 0, fmt.Errorf("parse maildirsize line %d: invalid size '%s': %w", lineNo, sizeStr, err)
		}
		total += v
	}

	if err := scanner.Err(); err != nil {
		return 0, fmt.Errorf("scan maildirsize failed: %w", err)
	}

	return total, nil
}

// domain.current_usage
func aggregateDomainUsage(ctx context.Context) {

	if atomic.LoadInt32(&domainUsageColumnEnsured) == 0 {
		if _, err := g.DB().Exec(ctx, "ALTER TABLE domain ADD COLUMN IF NOT EXISTS current_usage BIGINT NOT NULL DEFAULT 0"); err != nil {
			g.Log().Warning(ctx, "ensure domain.current_usage column failed", err)
		}
		atomic.StoreInt32(&domainUsageColumnEnsured, 1)
	}

	type dRow struct {
		Domain string
		Usage  int64

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Check permissions/ownership of the maildirsize file (must be readable by the mail service user, e.g. vmail)
  2. Test underlying storage health (dmesg for I/O errors, remount NFS)
  3. Re-run the used-space update; the failure may be transient
  4. Fall back to recomputing usage from the Maildir directory tree when maildirsize is unreadable
Defensive patterns

Strategy: retry

Validate before calling

f, err := os.Open(path)
if err != nil { return err }
if info, err := f.Stat(); err != nil || !info.Mode().IsRegular() {
    return fmt.Errorf("%s is not a readable regular file", path)
}

Try / catch

total, err := readMaildirsize(path)
if err != nil {
    if strings.Contains(err.Error(), "scan maildirsize failed") {
        // transient I/O — retry, then fall back to recalc
        if total, rerr := readMaildirsize(path); rerr == nil { return total, nil }
        return recalcUsageFromMaildir(filepath.Dir(path))
    }
    return err
}

Prevention

When it happens

Trigger: scanner.Err() returns non-nil after reading maildirsize: OS-level read failure such as permission denied, I/O error, or interruption while reading the file.

Common situations: Mailbox files owned by the wrong user (vmail permissions); NFS stale handle or timeout on network storage; disk hardware errors on the mail volume.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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