Skip to content

genie-api ignores [services.api].url — hardcodes listen on 127.0.0.1:3080 #140

Description

@kiannidev

Summary

genie-api always binds to 127.0.0.1:3080, while health probes, genie-ctl, and the dashboard Services row read [services.api].url from geniepod.toml. If an operator changes only the configured URL (e.g. for a second local instance on port 4080), probes and CLI target the new port but genie-api still listens on :3080, producing false DOWN signals and a broken dashboard.

This is the same class of config drift as #121 ([core].port vs [services.core].url), but for the dashboard service itself.

Duplicate check

Searched open/closed issues and PRs (May 2026). Related work fixed probe/proxy paths only, not the API server bind address:

Item Notes
#90 / PR #102 genie-ctl / dashboard proxies to genie-core now use Config::core_http_addr().
#103#127 genie-ctl / dashboard probe genie-api and HA from [services.*].url.
No existing issue Nothing filed for genie-api listen address ignoring config.

Steps to reproduce

  1. Set a non-default API URL while leaving the binary unchanged:

    [services.api]
    url = "http://127.0.0.1:4080/api/status"
    systemd_unit = "genie-api.service"
  2. Start the stack:

    GENIEPOD_CONFIG=/path/to/geniepod.toml ./target/release/genie-api
    GENIEPOD_CONFIG=/path/to/geniepod.toml ./target/release/genie-health
  3. Observe bind vs config:

    # Server still listens on 3080 (hardcoded in main.rs)
    ss -ltnp | grep -E '3080|4080'
    
    # Probes target 4080 per TOML
    curl -sf http://127.0.0.1:4080/api/status   # fails (connection refused)
    curl -sf http://127.0.0.1:3080/api/status   # succeeds
  4. genie-ctl health / dashboard Services row for api report unhealthy while the process is up on the wrong port.

Expected behavior

  • Single source of truth for where genie-api listens, aligned with [services.api].url (or explicit [api].port / [api].bind_host mirroring [core]).
  • Health monitor, dashboard latency row, and genie-ctl agree with the actual listen socket.
  • Default config (:3080) unchanged.

Actual behavior

crates/genie-api/src/main.rs hardcodes the bind address:

let bind_addr = "127.0.0.1:3080";

Meanwhile genie-core correctly uses config.core.port and config.core.bind_host at startup.

Suggested fix

  1. Add ApiConfig (or reuse parsed host/port from [services.api].url) in genie-common, e.g.:

    pub fn api_http_addr(&self) -> String { /* parse services.api.url or [api] section */ }
    pub fn api_status_url(&self) -> String { format!("http://{}/api/status", self.api_http_addr()) }
  2. genie-api: http::serve(&config.api_http_addr(), config) instead of a literal.

  3. Optional: At Config::load(), tracing::warn! if services.api.url port disagrees with the derived listen port (same pattern proposed for [services.core].url drifts from [core].port — health monitor and dashboard probe wrong port #121).

  4. Tests: genie-common unit test — URL http://127.0.0.1:4080/api/status → bind addr 127.0.0.1:4080.

Acceptance criteria

  • With [services.api].url = "http://127.0.0.1:4080/api/status", genie-api listens on 127.0.0.1:4080.
  • genie-health, dashboard /api/services api row, and genie-ctl health all agree when the service is healthy.
  • Default TOML (:3080) has no regression.

Hardware / version

  • Hardware: Non-Jetson dev host (logic-only)
  • Version: main @ clone time (2026-05-22)

Related

  • #121 — same drift pattern for genie-core health URL
  • #99 / PR #102 — core proxy addressing (already fixed)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions