koala73/worldmonitor · error · APIError

HTTP #{status}: #{body}

Error message

HTTP #{status}: #{body}

What it means

Raised as WorldMonitor::APIError by Client#get (line 128) when a REST GET returns a status outside the 200..299 range. The request completed at the transport layer but the server rejected or failed it. The message formats the status, the parsed body (truncated to 300 chars via Client.truncate), and an appended AUTH_HINT when status == 401 (line 56). APIError exposes .status and .body readers.

Source

Thrown at sdk/ruby/lib/worldmonitor.rb:128

    # List MCP resources (public).
    def list_resources
      rpc("resources/list")
    end

    # GET a raw REST path (host-relative, e.g. "/api/health").
    def get(path, params = {})
      raise ArgumentError, "get() needs a host-relative API path starting with '/'" unless path.start_with?("/")

      url = base_url + path
      query = stringify_keys(params)
      url += "?#{URI.encode_www_form(query.map { |k, v| [k, stringify_value(v)] })}" unless query.empty?
      status, content_type, body = @transport.call(
        { url: url, method: "GET", headers: headers(accept: "application/json") },
        timeout
      )
      value = self.class.parse_body(body, content_type)
      raise APIError.new(status, value) unless (200..299).cover?(status)

      value
    end

    # API status / health check.
    def health
      get("/api/health")
    end

    # -- curated helpers over the highest-traffic MCP tools -------------------
    # Every other tool is reachable via call_tool(), so this table stays small
    # and mirrors the npm CLI's curated commands one-to-one.

    # Live global situation brief.
    def world_brief(args = {})
      call_tool("get_world_brief", args)
    end

View on GitHub (pinned to ffec79ac33)

Solutions

  1. Inspect e.status and e.body: 401 → set api_key: or WORLDMONITOR_API_KEY; 404 → verify base_url and path; 429 → back off; 5xx → retry with jitter.
  2. Print client.base_url to confirm it is https://api.worldmonitor.app unless self-hosting.
  3. Prefer client.health over ad-hoc paths so the path stays correct across SDK versions.
  4. Wrap the call in rescue WorldMonitor::APIError and branch on status instead of letting any non-2xx propagate.

Example fix

# before
data = client.get('/api/bootstrap')
# after
begin
  data = client.get('/api/bootstrap')
rescue WorldMonitor::APIError => e
  raise 'Set WORLDMONITOR_API_KEY' if e.status == 401
  raise if (200..299).cover?(e.status)
  sleep 2 ** retry and retry if e.status == 429 || e.status >= 500
  raise
end
Defensive patterns

Strategy: try-catch

Validate before calling

# No request can be pre-validated for a server-side 4xx/5xx, but you can
# gate the call on a known-good base_url:
raise 'base_url must be https' unless client.base_url.start_with?('https://')

Type guard

def api_error?(exc)
  exc.is_a?(WorldMonitor::APIError)
end

def retriable?(exc)
  exc.is_a?(WorldMonitor::APIError) && [429, 500, 502, 503, 504].include?(exc.status)
end

Try / catch

begin
  data = client.get('/api/bootstrap')
rescue WorldMonitor::APIError => e
  case e.status
  when 401 then raise 'Set WORLDMONITOR_API_KEY'
  when 429, 500..504 then sleep(2 ** retry_count) and retry if retry_count < 3
  else raise
  end
rescue WorldMonitor::Error
  raise
end

Prevention

When it happens

Trigger: Calling client.get('/api/health'), client.get('/api/bootstrap'), or any host-relative REST path whose response is 401 (no/invalid X-WorldMonitor-Key), 404 (unknown path or wrong base_url), 429 (rate limited), or 500/502/503 (gateway failure). Also fires when WORLDMONITOR_BASE_URL is overridden to a host serving a non-success status for the path.

Common situations: Self-hosted or preview deployment where /api/health is not routed (404). A WORLDMONITOR_BASE_URL override that is mistyped or carries an extra path segment. API key missing in the deployed environment (401 on key-gated endpoints). Burst traffic tripping the rate limiter (429). Transient 5xx during a deploy window.

Related errors


AI-assisted analysis of koala73/worldmonitor@ffec79ac33 (2026-08-12). Data as JSON: /api/errors/d89bd4e318a4b482. Report an issue: GitHub.