Skip to content

Conversation

galzilber
Copy link
Contributor

@galzilber galzilber commented Sep 11, 2025

  • I have added tests that cover my changes.
  • If adding a new instrumentation or changing an existing one, I've added screenshots from some observability platform showing the change.
  • PR name follows conventional commits format: feat(instrumentation): ... or fix(instrumentation): ....
  • (If applicable) I have updated the documentation accordingly.

Important

Fixes Authorization header in wait_for_result of stream_client.py to resolve unauthorized errors due to dual bearer tokens.

  • Bug Fix:
    • Fixes Authorization header in wait_for_result function of stream_client.py to prevent dual bearer token issue causing unauthorized errors.
  • Behavior:
    • Ensures correct header format for server expectations, improving connection reliability.
    • No changes to function signatures or other headers.

This description was created by Ellipsis for df20bca. You can customize this summary. It will automatically update as commits are pushed.


at the current state the api service receiving duel bearer
so the request been failed due unauthorized
image

Summary by CodeRabbit

  • Bug Fixes
    • Corrected Authorization header handling in evaluator streaming requests to use the configured value as-is, improving compatibility with non-Bearer schemes and preventing duplicate prefixes. No API changes.
    • Action required: If you previously relied on automatic “Bearer ” prefixing, ensure your Authorization header includes the appropriate scheme (e.g., “Bearer ”).

Copy link

coderabbitai bot commented Sep 11, 2025

Walkthrough

The change updates the Authorization header handling in wait_for_result within packages/traceloop-sdk/traceloop/sdk/evaluator/stream_client.py, removing the hardcoded "Bearer " prefix and passing through the header value from the underlying client unchanged. No other logic or public interfaces are modified.

Changes

Cohort / File(s) Summary of Changes
Evaluator streaming client header handling
packages/traceloop-sdk/traceloop/sdk/evaluator/stream_client.py
In wait_for_result, changed Authorization header from Bearer {client.headers['Authorization']} to raw client.headers['Authorization']. All other request flow and error handling unchanged.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant StreamClient as Evaluator StreamClient
  participant Service as Remote Service

  Caller->>StreamClient: wait_for_result(task_id)
  Note right of StreamClient: Build URL and headers
  StreamClient->>Service: GET /result/{task_id}\nAuthorization: <client.headers['Authorization']>
  alt Success
    Service-->>StreamClient: 200 OK (streamed/result)
    StreamClient-->>Caller: Return result
  else Error
    Service-->>StreamClient: Error status
    StreamClient-->>Caller: Raise/propagate error
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Pre-merge checks (3 passed)

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "fix(sdk): dual bearer send via httpx" succinctly identifies the primary issue (duplicate Bearer token sent by httpx) and aligns with the PR changes that adjust Authorization header construction to send the raw API key; it is short and follows conventional-commit style.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Poem

I nibbled the header, light as air,
Plucked “Bearer” off with careful care.
Now raw and clean, it hops along—
A token true, neither short nor long.
In streams we wait, ears tall and bright,
For results to land by moonlit night. 🐇✨

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch gz/fix-httpx-duel-bearer

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed everything up to b3c06fa in 46 seconds. Click for details.
  • Reviewed 13 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 1 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/traceloop-sdk/traceloop/sdk/client/client.py:57
  • Draft comment:
    Removed 'Bearer ' prefix from the Authorization header in AsyncClient. Ensure that the API endpoint now expects the raw API key and not a bearer token format.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.

Workflow ID: wflow_4mRUuYljxrYdNYOh

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

@galzilber galzilber changed the title fix: duel bearer send via httpx fix(sdk): dual bearer send via httpx Sep 11, 2025
Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

Looks good to me! 👍

Reviewed df20bca in 31 seconds. Click for details.
  • Reviewed 26 lines of code in 2 files
  • Skipped 0 files when reviewing.
  • Skipped posting 2 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. packages/traceloop-sdk/traceloop/sdk/client/client.py:57
  • Draft comment:
    Good fix: Using 'Bearer {api_key}' directly ensures the header matches server expectations. Ensure that all clients consistently follow this format.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
2. packages/traceloop-sdk/traceloop/sdk/evaluator/stream_client.py:24
  • Draft comment:
    Removing the redundant 'Bearer' prefix avoids sending 'Bearer Bearer ...' and fixes auth failures.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None

Workflow ID: wflow_piziuZbz6r1lZ9R7

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
packages/traceloop-sdk/traceloop/sdk/evaluator/stream_client.py (3)

29-29: Normalize URL join to avoid accidental double slashes and match existing pattern.

Use the same pattern as your sync client (/v2/{...} with lstrip('/')):

-            full_stream_url = f"{self.client.base_url}/v2{stream_url}"
+            full_stream_url = f"{self.client.base_url}/v2/{stream_url.lstrip('/')}"

35-35: SSE-friendly timeouts: avoid read timeout for long-lived streams.

-                timeout=httpx.Timeout(timeout_in_sec),
+                timeout=httpx.Timeout(connect=timeout_in_sec, read=None),

55-55: Add concrete type for response parameter.

-    async def _handle_sse_response(self, response) -> ExecutionResponse:
+    async def _handle_sse_response(self, response: httpx.Response) -> ExecutionResponse:
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b3c06fa and df20bca.

📒 Files selected for processing (1)
  • packages/traceloop-sdk/traceloop/sdk/evaluator/stream_client.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Store API keys only in environment variables/secure vaults; never hardcode secrets in code
Use Flake8 for code linting and adhere to its rules

Files:

  • packages/traceloop-sdk/traceloop/sdk/evaluator/stream_client.py
🧬 Code graph analysis (1)
packages/traceloop-sdk/traceloop/sdk/evaluator/stream_client.py (1)
packages/traceloop-sdk/traceloop/sdk/client/http.py (1)
  • get (39-58)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Test Packages (3.11)
  • GitHub Check: Test Packages (3.12)
  • GitHub Check: Test Packages (3.10)
  • GitHub Check: Lint
  • GitHub Check: Build Packages (3.11)

Comment on lines 23 to 27
headers = {
"Authorization": f"Bearer {self.client.headers.get('Authorization')}",
"Authorization": self.client.headers.get('Authorization'),
"Accept": "text/event-stream",
"Cache-Control": "no-cache",
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Don’t override Authorization; guard against None to avoid runtime error and rely on client auth.

If self.client was configured with auth=... (not a default header), self.client.headers.get('Authorization') will be None, and passing {"Authorization": None} can raise a TypeError in httpx. Also, you can let the client’s configured auth/header flow through without re-specifying it here, which avoids any “dual Bearer” regressions.

Preferred fix (remove explicit Authorization override and let the client send it if configured):

-            headers = {
-                "Authorization": self.client.headers.get('Authorization'),
-                "Accept": "text/event-stream",
-                "Cache-Control": "no-cache",
-            }
+            headers = {
+                "Accept": "text/event-stream",
+                "Cache-Control": "no-cache",
+            }

Minimal alternative (only add the header if present):

-            headers = {
-                "Authorization": self.client.headers.get('Authorization'),
-                "Accept": "text/event-stream",
-                "Cache-Control": "no-cache",
-            }
+            _auth = self.client.headers.get('Authorization')
+            headers = {
+                "Accept": "text/event-stream",
+                "Cache-Control": "no-cache",
+            }
+            if _auth:
+                headers["Authorization"] = _auth

Run to confirm no other places still prepend "Bearer " explicitly:


🏁 Script executed:

#!/bin/bash
rg -nP -C2 --type=py '\bAuthorization\b.*Bearer'
rg -nP -C2 --type=py 'httpx\.(AsyncClient|Client)\s*\([^)]*\bheaders\s*='

Length of output: 3600


Don't override Authorization — remove or guard against None and centralize auth in the client.

Passing Authorization: None can raise httpx errors and the repo already sets "Bearer ..." in multiple places; standardize on the client's auth/header. Found explicit "Bearer" usage in:

  • packages/traceloop-sdk/traceloop/sdk/images/image_uploader.py
  • packages/traceloop-sdk/traceloop/sdk/fetcher.py
  • packages/traceloop-sdk/traceloop/sdk/init.py
  • packages/traceloop-sdk/traceloop/sdk/client/http.py
  • packages/traceloop-sdk/traceloop/sdk/client/client.py

Preferred fix (remove explicit Authorization override and let the client send it if configured):

-            headers = {
-                "Authorization": self.client.headers.get('Authorization'),
-                "Accept": "text/event-stream",
-                "Cache-Control": "no-cache",
-            }
+            headers = {
+                "Accept": "text/event-stream",
+                "Cache-Control": "no-cache",
+            }

Minimal alternative (only add the header if present):

-            headers = {
-                "Authorization": self.client.headers.get('Authorization'),
-                "Accept": "text/event-stream",
-                "Cache-Control": "no-cache",
-            }
+            _auth = self.client.headers.get('Authorization')
+            headers = {
+                "Accept": "text/event-stream",
+                "Cache-Control": "no-cache",
+            }
+            if _auth:
+                headers["Authorization"] = _auth
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
headers = {
"Authorization": f"Bearer {self.client.headers.get('Authorization')}",
"Authorization": self.client.headers.get('Authorization'),
"Accept": "text/event-stream",
"Cache-Control": "no-cache",
}
headers = {
"Accept": "text/event-stream",
"Cache-Control": "no-cache",
}
🤖 Prompt for AI Agents
In packages/traceloop-sdk/traceloop/sdk/evaluator/stream_client.py around lines
23 to 27, the code overwrites the Authorization header with a possible None
value which can cause httpx errors and duplicates auth handling; remove the
explicit "Authorization" entry from the headers dict so the configured
client-level auth/headers are used, or if you prefer the minimal change only set
Authorization when self.client.headers.get('Authorization') is truthy (guard
against None); centralize authorization in the shared client implementation
instead of overriding it here.

@nirga nirga merged commit a189d2d into main Sep 13, 2025
12 checks passed
@nirga nirga deleted the gz/fix-httpx-duel-bearer branch September 13, 2025 11:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants