Billionmail/BillionMail · error
parse maildirsize line %d: invalid size '%s': %w
Error message
parse maildirsize line %d: invalid size '%s': %w
What it means
readMaildirsize parses Dovecot's maildirsize file to compute a mailbox's used space. Each data line starts with a byte count that may be suffixed with 'S' (messages) which is stripped before parsing. This error is thrown when strconv.ParseInt cannot convert the size token to an int64, meaning the maildirsize file is corrupted or in an unexpected format.
Source
Thrown at core/internal/service/mail_boxes/update_used_space.go:226
}
parts := strings.Fields(line)
if len(parts) == 0 {
continue
}
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)
}View on GitHub (pinned to fc36c76c05)
Solutions
- Inspect the maildirsize file at the reported line number and fix or remove the malformed size token
- Delete the maildirsize file and let Dovecot recalculate it (rebuild quota index)
- Ensure quota rules are consistent so tools writing maildirsize use the standard '<bytes> <count>' format
- Wrap ParseInt with a guard that skips empty/unparseable tokens instead of failing the whole read
Example fix
// before
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)
}
// after
if sizeStr == "" {
continue // skip blank size token
}
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)
} Defensive patterns
Strategy: validation
Validate before calling
data, err := os.ReadFile(maildirsizePath)
if err != nil { return err }
for i, line := range strings.Split(string(data), "\n") {
if i == 0 { continue } // header
sizeStr := strings.TrimSuffix(strings.Fields(line)[0], "S")
if _, err := strconv.ParseInt(sizeStr, 10, 64); err != nil {
return fmt.Errorf("malformed maildirsize line %d", i+1)
}
} Type guard
func isValidMaildirSize(tok string) bool {
_, err := strconv.ParseInt(strings.TrimSuffix(tok, "S"), 10, 64)
return err == nil
} Try / catch
total, err := readMaildirsize(path)
if errors.Is(err, strconv.ErrSyntax) || strings.Contains(err.Error(), "invalid size") {
log.Warn("corrupt maildirsize, rebuilding")
os.Remove(path) // let Dovecot recalc
return recalcUsageFromMaildir(path)
}
if err != nil { return err } Prevention
- Never hand-edit maildirsize; delete it and let Dovecot rebuild
- Monitor for disk-full events that truncate quota files
- Validate the file after any maildir migration or NFS failover
When it happens
Trigger: A maildirsize line whose first whitespace-separated field is not a decimal integer (after trimming a trailing 'S'), e.g. alphabetic garbage, truncated writes, or a header line miscounted as a data line.
Common situations: Disk-full or crash during maildirsize write leaving a partial line; manual edits of the maildirsize file; a mail delivery tool writing a nonstandard size field; NFS corruption of the maildir metadata.
Related errors
- open maildirsize failed: %w
- scan maildirsize failed: %w
- DNS automated resolution failed: ClientID, ClientSecret or T
- DNS automated resolution failed: APIKey or APISecret is empt
- Failed to get configuration
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/07bb1f445926a1d2.
Report an issue: GitHub.