Billionmail/BillionMail · error

fail2ban value can only be y/n or 1/0

Error message

fail2ban value can only be y/n or 1/0

What it means

The FAIL2BAN_INIT/fail2ban key is a boolean-style toggle and validateConfigValue only accepts the literal strings y, n, 1 or 0. Any other value (true/false, yes/no, on/off) is rejected because the value is written directly into fail2ban/service configuration that expects this restricted alphabet.

Source

Thrown at core/internal/controller/settings/settings.go:234

			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")
	}

	return nil
}

View on GitHub (pinned to fc36c76c05)

Solutions

  1. Send exactly one of: 'y', 'n', '1' or '0'
  2. Map booleans before the call: true→'1', false→'0'
  3. Normalize case to lowercase ('Y'→'y') if your source data is uppercase
  4. Verify the stored value after saving by reading the config back

Example fix

// before
FAIL2BAN_INIT = true
// after
FAIL2BAN_INIT = 1
Defensive patterns

Strategy: validation

Validate before calling

const ALLOWED = new Set(['y','n','1','0']);
if (!ALLOWED.has(flag)) throw new Error('fail2ban value can only be y/n or 1/0');

Type guard

function isFail2banFlag(v: string): v is 'y'|'n'|'1'|'0' {
  return v === 'y' || v === 'n' || v === '1' || v === '0';
}

Try / catch

try {
  await api.setSystemConfigKey('FAIL2BAN_INIT', flag);
} catch (e) {
  if (String(e.message).includes('fail2ban')) {
    notify('Use exactly y, n, 1 or 0 (lowercase)');
  } else throw e;
}

Prevention

When it happens

Trigger: Calling SetSystemConfig/SetSystemConfigKey with FAIL2BAN_INIT set to 'true', 'false', 'yes', 'no', 'enabled', 'Y'/'N' if the check is case-sensitive, or an empty string.

Common situations: Frontends or scripts send JSON booleans serialized as 'true'/'false', or users type 'yes'/'no' out of habit; case-sensitivity trips values like 'Yes'.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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