{"record":{"id":"cf49cb76923edfe5","repo":"commaai/openpilot","slug":"call-to-path-failed-with-r-status-code","errorCode":null,"errorMessage":"Call to {path} failed with {r.status_code}","messagePattern":"Call to (.+?) failed with (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"openpilot/tools/lib/github_utils.py","lineNumber":31,"sourceCode":"  @property\n  def API_ROUTE(self):\n    return f\"https://api.github.com/repos/{self.OWNER}/{self.API_REPO}\"\n\n  @property\n  def DATA_ROUTE(self):\n    return f\"https://api.github.com/repos/{self.OWNER}/{self.DATA_REPO}\"\n\n  def api_call(self, path, data=\"\", method=HTTPMethod.GET, accept=\"\", data_call=False, raise_on_failure=True):\n    token = self.DATA_TOKEN if data_call else self.API_TOKEN\n    if token:\n      headers = {\"Authorization\": f\"Bearer {self.DATA_TOKEN if data_call else self.API_TOKEN}\", \\\n                 \"Accept\": f\"application/vnd.github{accept}+json\"}\n    else:\n      headers = {}\n    path = f'{self.DATA_ROUTE if data_call else self.API_ROUTE}/{path}'\n    r = requests.request(method, path, headers=headers, data=data)\n    if not r.ok and raise_on_failure:\n      raise Exception(f\"Call to {path} failed with {r.status_code}\")\n    else:\n      return r\n\n  def upload_file(self, bucket, path, file_name):\n    with open(path, \"rb\") as f:\n      encoded = base64.b64encode(f.read()).decode()\n\n      # check if file already exists\n      sha = self.get_file_sha(bucket, file_name)\n      sha = f'\"sha\":\"{sha}\",' if sha else ''\n\n      data = f'{{\"message\":\"uploading {file_name}\", \\\n                    \"branch\":\"{bucket}\", \\\n                    \"committer\":{{\"name\":\"Vehicle Researcher\", \"email\": \"user@comma.ai\"}}, \\\n                    {sha} \\\n                    \"content\":\"{encoded}\"}}'\n      github_path = f\"contents/{file_name}\"\n      self.api_call(github_path, data=data, method=HTTPMethod.PUT, data_call=True)","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/commaai/openpilot/blob/516ec1e68203439a73f340f1d0b3b91eabc626ee/openpilot/tools/lib/github_utils.py#L13-L49","documentation":"github_utils api_call() wraps requests.request; when the GitHub API (or the configured data route) returns a non-OK status and raise_on_failure is True (default), it raises a bare Exception with the path and status code. Common statuses: 401 bad/expired token, 403 rate limit, 404 missing repo/file, 422 validation.","triggerScenarios":"Any api_call()/upload_file()/get_file_sha() on the github data repo — uploading route data with an invalid GITHUB_TOKEN, hitting the hourly rate limit, or referencing a repo the token cannot see.","commonSituations":"Expired personal access token; un-set token in CI hitting 401/403 rate limits; wrong OWNER/DATA_REPO config; pushing a file larger than GitHub allows.","solutions":["Check the status code in the message: 401/403 => fix the token (GITHUB_TOKEN env / auth config), 403 with 'rate limit' => wait or authenticate, 404 => verify repo name/path","Test the token: curl -H \"Authorization: Bearer $TOKEN\" https://api.github.com/user","Pass raise_on_failure=False if you want to handle the response yourself instead of an exception"],"exampleFix":"# before\napi.api_call(f'contents/{bucket}/{file_name}', data=data, method=HTTPMethod.PUT)\n\n# after\nr = api.api_call(f'contents/{bucket}/{file_name}', data=data, method=HTTPMethod.PUT, raise_on_failure=False)\nif r.status_code in (403, 429):\n    time.sleep(int(r.headers.get('X-RateLimit-Reset', time.time() + 60)) - time.time())\n    r = api.api_call(f'contents/{bucket}/{file_name}', data=data, method=HTTPMethod.PUT)","handlingStrategy":"retry","validationCode":"def token_valid(token: str) -> bool:\n    r = requests.get('https://api.github.com/user', headers={'Authorization': f'Bearer {token}'})\n    return r.status_code == 200","typeGuard":null,"tryCatchPattern":"r = api.api_call(path, raise_on_failure=False)\nif r.status_code == 403 and 'rate limit' in r.text:\n    wait_for_rate_limit_reset(r)\n    r = api.api_call(path)\nr.raise_for_status()","preventionTips":["Check token validity once at job start, not per-call","Handle 403 rate limits by sleeping until X-RateLimit-Reset","Use raise_on_failure=False when you want status-based logic instead of exceptions"],"tags":["network","github-api","auth","rate-limit"],"backgroundTag":null,"analyzedSha":"516ec1e68203439a73f340f1d0b3b91eabc626ee","analyzedAt":"2026-08-15T00:17:37.461Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}