{"record":{"id":"44d8ed53cd779346","repo":"BerriAI/litellm","slug":"failed-to-get-file-metadata-for-file-path-e","errorCode":null,"errorMessage":"Failed to get file metadata for '{file_path}': {e}","messagePattern":"Failed to get file metadata for '(.+?)': (.+?)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/integrations/bitbucket/bitbucket_client.py","lineNumber":243,"sourceCode":"        try:\n            # Use GET with Range header to get just the headers (HEAD equivalent)\n            headers: Final = self.headers.copy()\n            headers[\"Range\"] = \"bytes=0-0\"  # Request only first byte to get headers\n\n            response: Final = self.http_handler.get(url, headers=headers)\n            response.raise_for_status()\n\n            return {\n                \"content_type\": response.headers.get(\"content-type\"),\n                \"content_length\": response.headers.get(\"content-length\"),\n                \"last_modified\": response.headers.get(\"last-modified\"),\n            }\n        except Exception as e:\n            # Check if it's an HTTP error\n            if hasattr(e, \"response\") and hasattr(e.response, \"status_code\"):\n                if e.response.status_code == 404:\n                    return None\n                raise Exception(f\"Failed to get file metadata for '{file_path}': {e}\")\n            else:\n                raise Exception(f\"Error getting file metadata for '{file_path}': {e}\")\n\n    def close(self):\n        \"\"\"Close the HTTP handler to free resources.\"\"\"\n        if hasattr(self, \"http_handler\"):\n            self.http_handler.close()\n","sourceCodeStart":225,"sourceCodeEnd":251,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/bitbucket/bitbucket_client.py#L225-L251","documentation":"Raised by BitBucketClient.get_file_metadata when the HEAD/GET for a file returns an HTTP error whose status is not 404 (which is mapped to None). The status is embedded only in the message text. So 401, 403, 429 and 5xx on the raw-file endpoint all surface here.","triggerScenarios":"Calling get_file_metadata('prompts/summary.prompt') with a token that can list but not read raw file contents (403), expired credentials (401), or BitBucket rate limiting (429) when polling metadata for many files in a loop.","commonSituations":"Polling loops that check file freshness via last_modified headers; branch restrictions that grant read on directory listings but not on src endpoints; heavy CI runs hitting rate limits.","solutions":["Check the embedded status code in the message first: 403 → extend token scopes, 401 → refresh token, 429 → slow down","Rate-limit metadata checks and cache results keyed by path","Verify the file path is relative to the repo root with no leading slash","Prefer checking get_file_content() if you need the body anyway — it maps 404 to None instead of raising"],"exampleFix":"# before\nmeta = client.get_file_metadata(\"prompts/summary.prompt\")\n\n# after\ntry:\n    meta = client.get_file_metadata(\"prompts/summary.prompt\")\nexcept Exception as e:\n    if \"403\" in str(e):\n        logger.error(\"Token lacks file read scope for this repo\")\n        raise\n    meta = None  # metadata is best-effort","handlingStrategy":"try-catch","validationCode":"# Skip metadata polling during rate-limit windows\nimport time\n_last_meta_call = 0.0\n\ndef metadata_allowed(min_interval_s: float = 1.0) -> bool:\n    global _last_meta_call\n    now = time.monotonic()\n    if now - _last_meta_call < min_interval_s:\n        return False\n    _last_meta_call = now\n    return True","typeGuard":null,"tryCatchPattern":"try:\n    meta = client.get_file_metadata(path)\nexcept Exception as e:\n    if \"404\" in str(e):\n        meta = None  # defensive; current code returns None for 404\n    elif \"429\" in str(e):\n        backoff_and_retry_later()\n    else:\n        raise","preventionTips":["Treat metadata as best-effort: cache it and degrade to None on failure","Ensure the token has raw file read scope, not just listing scope","Rate-limit metadata polls in loops"],"tags":["bitbucket","metadata","permissions"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}