{"record":{"id":"b5842806bb777711","repo":"koala73/worldmonitor","slug":"get-needs-a-host-relative-api-path-starting-with-b58428","errorCode":null,"errorMessage":"get() needs a host-relative API path starting with '/'","messagePattern":"get\\(\\) needs a host-relative API path starting with '/'","errorType":"validation","errorClass":"ArgumentError","httpStatus":null,"severity":"warning","filePath":"sdk/ruby/lib/worldmonitor.rb","lineNumber":118,"sourceCode":"\n    # List every MCP tool (public - no key needed).\n    def list_tools\n      rpc(\"tools/list\")\n    end\n\n    # List MCP prompt templates (public).\n    def list_prompts\n      rpc(\"prompts/list\")\n    end\n\n    # List MCP resources (public).\n    def list_resources\n      rpc(\"resources/list\")\n    end\n\n    # GET a raw REST path (host-relative, e.g. \"/api/health\").\n    def get(path, params = {})\n      raise ArgumentError, \"get() needs a host-relative API path starting with '/'\" unless path.start_with?(\"/\")\n\n      url = base_url + path\n      query = stringify_keys(params)\n      url += \"?#{URI.encode_www_form(query.map { |k, v| [k, stringify_value(v)] })}\" unless query.empty?\n      status, content_type, body = @transport.call(\n        { url: url, method: \"GET\", headers: headers(accept: \"application/json\") },\n        timeout\n      )\n      value = self.class.parse_body(body, content_type)\n      raise APIError.new(status, value) unless (200..299).cover?(status)\n\n      value\n    end\n\n    # API status / health check.\n    def health\n      get(\"/api/health\")\n    end","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/koala73/worldmonitor/blob/ffec79ac339946fd2d24e85845da5755dcaa534b/sdk/ruby/lib/worldmonitor.rb#L100-L136","documentation":"Raised as ArgumentError by Client#get (line 118) when the path argument does not start with '/'. This is a synchronous pre-flight validation — no network call is made. The guard exists because get() concatenates base_url + path directly (line 120), so a non-slash path would either silently join incorrectly or hit the wrong endpoint. It forces callers to pass host-relative paths (e.g. '/api/health'), not bare names or absolute URLs.","triggerScenarios":"Calling client.get('api/health') (missing leading slash), client.get('https://api.worldmonitor.app/api/health') (absolute URL instead of host-relative), client.get('') (empty string), or a dynamically built path like client.get(\"api/#{endpoint}\") that omits the slash. Also triggers when interpolating a config value that does not carry a leading slash.","commonSituations":"Copy-pasting a path from a browser address bar (which drops the leading slash). Building a path from a variable that was stripped. Passing a full URL out of habit. Treating get() like Faraday/HTTParty which accept absolute URLs.","solutions":["Prefix the path with '/': call client.get('/api/health'), not client.get('api/health').","If the path is dynamic, normalize it: client.get('/' + path.sub(%r{^/}, '')) to guarantee exactly one leading slash.","For absolute URLs, extract the path with URI.parse(url).request_uri before passing it.","Prefer the curated helpers (client.health, etc.) which already use correct host-relative paths."],"exampleFix":"# before\nclient.get('api/health')\n# after\npath = 'api/health'\nclient.get('/' + path.sub(%r{\\A/+}, ''))","handlingStrategy":"validation","validationCode":"# Normalize the path before calling get so a missing slash never reaches the SDK.\ndef safe_get(client, path, **params)\n  raise ArgumentError, 'path is required' if path.nil? || path.empty?\n  path = '/' + path.sub(%r{\\A/+}, '')\n  client.get(path, **params)\nend","typeGuard":"def host_relative_path?(path)\n  path.is_a?(String) && path.start_with?('/') && !path.start_with?('//')\nend","tryCatchPattern":"begin\n  client.get(path)\nrescue ArgumentError => e\n  if e.message.start_with?(\"get() needs a host-relative\")\n    path = '/' + path.to_s.sub(%r{\\A/+}, '')\n    retry\n  end\n  raise\nend","preventionTips":["Always pass a literal leading slash: '/api/health', never 'api/health'.","For dynamic paths, normalize with '/' + path.sub(%r{\\A/+}, '') at the call site.","For absolute URLs, extract the path via URI.parse(url).request_uri first.","Prefer curated helpers (client.health) over raw get() so the path is always correct."],"tags":["ruby","validation","argument-error","sdk"],"backgroundTag":null,"analyzedSha":"ffec79ac339946fd2d24e85845da5755dcaa534b","analyzedAt":"2026-08-12T11:24:56.012Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}