Billionmail/BillionMail · error
invalid timezone
Error message
invalid timezone
What it means
validateConfigValue checks the TZ/timezone key with public.IsValidTimezone and rejects values that are not IANA timezone identifiers. The timezone is propagated into container and service configs, so an unknown value would cause time-dependent features (logs, scheduling, warmup) to misbehave.
Source
Thrown at core/internal/controller/settings/settings.go:228
case "SMTP_PORT", "SMTPS_PORT", "SUBMISSION_PORT", "IMAP_PORT", "IMAPS_PORT", "POP_PORT", "POPS_PORT", "HTTP_PORT", "HTTPS_PORT", "REDIS_PORT",
"smtp", "smtps", "submission", "imap", "imaps", "pop", "pops", "http", "https", "redis_port":
// Port: 1-65535
port := public.ParseInt(value)
if port < 1 || port > 65535 {
return fmt.Errorf("port must be between 1-65535")
}
case "IPV4_NETWORK", "ipv4_network":
// IPv4 network: CIDR format
if !public.IsValidCIDR(value) {
return fmt.Errorf("IPv4 network format is incorrect, please use CIDR format (e.g. 192.168.1.0/24)")
}
case "TZ", "timezone":
// Timezone: check if it is a valid timezone
if !public.IsValidTimezone(value) {
return fmt.Errorf("invalid timezone")
}
case "FAIL2BAN_INIT", "fail2ban":
// fail2ban: only allowed y/n or 1/0
if value != "y" && value != "n" && value != "1" && value != "0" {
return fmt.Errorf("fail2ban value can only be y/n or 1/0")
}
case "RETENTION_DAYS", "retention_days":
// retention_days: must be a number
if _, err := strconv.Atoi(value); err != nil {
return fmt.Errorf("retention_days must be a number")
}
}
// General character check: not allowed dangerous characters
if public.ContainsDangerousChars(value) {
return fmt.Errorf("configuration value contains illegal characters")
}View on GitHub (pinned to fc36c76c05)
Solutions
- Use an IANA timezone identifier, e.g. 'America/New_York' or 'Europe/Berlin'
- Check the name against the IANA tz database (or Go's time.LoadLocation) before saving
- Replace fixed-offset strings like 'UTC+2' with the corresponding zone name
- Trim whitespace and fix casing to match the canonical zone name
Example fix
// before TZ = EST // after TZ = America/New_York
Defensive patterns
Strategy: validation
Validate before calling
function isValidTimezone(tz: string): boolean {
try { Intl.DateTimeFormat(undefined, { timeZone: tz }); return true; }
catch { return false; }
}
if (!isValidTimezone(tz)) throw new Error('invalid timezone'); Type guard
function isIANAZone(v: string): v is string {
return /^[A-Za-z]+\/[A-Za-z_+-]+$/.test(v) || v === 'UTC';
} Try / catch
try {
await api.setSystemConfigKey('TZ', tz);
} catch (e) {
if (String(e.message).includes('invalid timezone')) {
notify('Use an IANA timezone name like Europe/Berlin');
} else throw e;
} Prevention
- Use IANA tz names, never GMT offsets or Windows zone names
- Pick from a timezone dropdown instead of free text
- Trim whitespace before sending
- Test with Intl.DateTimeFormat or time.LoadLocation equivalent first
When it happens
Trigger: Setting TZ to abbreviations ('EST', 'CET'), offsets ('UTC+2'), a made-up zone ('Europe/Berlin '), wrong casing ('america/new_york' if the checker is case-sensitive), or a zone not present in the tz database.
Common situations: Admins copy Windows timezone names ('W. Europe Standard Time') or GMT offsets from other systems instead of IANA names like 'Europe/Berlin' or 'America/New_York'.
Related errors
- hostname format is incorrect
- port must be between 1-65535
- IPv4 network format is incorrect, please use CIDR format (e.
- fail2ban value can only be y/n or 1/0
- retention_days must be a number
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/f02f1a8cbe43831d.
Report an issue: GitHub.