rathole-org/rathole · error

Neither of `[server]` or `[client]` is defined

Error message

Neither of `[server]` or `[client]` is defined

What it means

The TOML config file parsed successfully but defines neither a `[server]` nor a `[client]` section, so there is nothing for rathole to run. `Config::from_str` requires at least one of the two role sections to be present and returns this error otherwise.

Solutions

  1. Add a `[server]` or `[client]` section to the config file passed to the binary
  2. Check that the config file you actually passed (-c path) is the role-specific one, not only the shared/common file
  3. Verify section headers are top-level, correctly spelled lowercase `[server]`/`[client]`, and not indented under another table

Example fix

# before
[transport]
type = "tcp"

# after
[client]
remote_addr = "example.com:2333"

[client.services]
ssh = { local_addr = "127.0.0.1:22" }
Defensive patterns

Strategy: validation

Validate before calling

let cfg = std::fs::read_to_string(path)?;
let raw: toml::Value = toml::from_str(&cfg)?;
if raw.get("server").is_none() && raw.get("client").is_none() {
    return Err(format!("{}: config has neither [server] nor [client]", path));
}

Prevention

When it happens

Trigger: Calling `Config::from_str` (or running the binary) with a config whose top-level tables are only things like `[transport]`/`[network]` (shared config include), a completely empty file, a config where the sections are misspelled or nested under another table, or a file with only comments.

Common situations: Users split config into a common file plus server/client files and run the binary against only the common file; typos like `[Server]` (case) or accidentally indenting the section so it lands inside another table; pointing `-c` at the wrong file.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of rathole-org/rathole@a292f7ed54 (2026-09-07). Data as JSON: /api/errors/6629dd9b57bb7eb6. Report an issue: GitHub.

Appendix: source

Thrown at src/config.rs:252

pub struct Config {
    pub server: Option<ServerConfig>,
    pub client: Option<ClientConfig>,
}

impl Config {
    fn from_str(s: &str) -> Result<Config> {
        let mut config: Config = toml::from_str(s).with_context(|| "Failed to parse the config")?;

        if let Some(server) = config.server.as_mut() {
            Config::validate_server_config(server)?;
        }

        if let Some(client) = config.client.as_mut() {
            Config::validate_client_config(client)?;
        }

        if config.server.is_none() && config.client.is_none() {
            Err(anyhow!("Neither of `[server]` or `[client]` is defined"))
        } else {
            Ok(config)
        }
    }

    fn validate_server_config(server: &mut ServerConfig) -> Result<()> {
        // Validate services
        for (name, s) in &mut server.services {
            s.name = name.clone();
            if s.token.is_none() {
                s.token = server.default_token.clone();
                if s.token.is_none() {
                    bail!("The token of service {} is not set", name);
                }
            }
        }

        Config::validate_transport_config(&server.transport, true)?;

View on GitHub (pinned to a292f7ed54)