Skip to content

fix(runner): keep the run credential when the public api base is unconfigured - #6281

Open
mmabrouk wants to merge 1 commit into
mainfrom
fix/runner-api-url-credential-attribution
Open

fix(runner): keep the run credential when the public api base is unconfigured#6281
mmabrouk wants to merge 1 commit into
mainfrom
fix/runner-api-url-credential-attribution

Conversation

@mmabrouk

Copy link
Copy Markdown
Member

The symptom

Every agent run on a self-hosted v0.114.0 deployment fails with:

Agent run failed: session 3f734241-... record log is unreadable; cannot rebuild the conversation

The rest of the app works. The error names the conversation record log, but the record log is not
the problem: the runner is calling the API with no Authorization header at all, so every
/sessions/* call comes back 401.

Before, on a deployment reachable at https://agenta.example.com:

[sessions] stream sessionOwned=true sessionId=... cred=MISSING
[sessions/records-query] query FAILED session=...: HTTP 401
[sessions/alive]        heartbeat HTTP 401 session=... turn=...
[sessions/persist]      DROPPED session=... after 6 retries: HTTP 401

After, same deployment, same configuration:

[sessions] WARNING: trace endpoint https://agenta.example.com/api/otlp/v1/traces matches no
configured Agenta ingest base (http://api:8000, https://cloud.agenta.ai/api), and AGENTA_API_URL
is not set, so the run credential cannot be attributed. Using it for platform calls anyway. Set
AGENTA_API_URL to this deployment's public api base (e.g. https://<host>/api) ...
[sessions] stream sessionOwned=true sessionId=... cred=present
[sessions/persist] ingest OK session=... idx=0 type=message

Why it happens

platformCredentialForRequest decides whether the run's Authorization header may authenticate the
runner's own calls back to the API. One header on the wire has two possible owners: this platform,
or a third-party OTLP collector the caller aimed the run at. Sending a collector's token to the
Agenta API would leak it, so da83e2b80b (new in v0.114.0) started gating the credential on
isAgentaIngest(endpoint).

That gate is a string comparison against AGENTA_API_INTERNAL_URL, AGENTA_API_URL, and the cloud
base. The two sides never line up on a normal self-hosted deployment:

  • The services container builds the run's trace endpoint from its own public base, so the run
    carries https://agenta.example.com/api/otlp/v1/traces.
  • The runner is configured with the in-network hop it actually calls, http://api:8000.

AGENTA_API_URL is what closes that gap, and the Compose files default it to empty
(AGENTA_API_URL: ${AGENTA_API_URL:-}, filled by shell interpolation). A deployment that never
exported it matches nothing, drops the credential, and fails 401 on every session call. Nothing is
written to the record log and nothing can be read back, which is why the failure surfaces four steps
away from its cause.

Kubernetes was never affected: the chart sets AGENTA_API_URL on the runner pod unconditionally.

The fix

The attribution is only decidable once the runner knows the public base, because the internal
hop never appears in a dispatched run. So arm the strict check only when the operator has supplied
the input that makes it correct:

  • AGENTA_API_URL set: unchanged. A non-matching endpoint really is someone else's collector, and
    the credential is dropped exactly as it is today.
  • AGENTA_API_URL unset: keep the credential (the behavior before the check existed) and log once
    per endpoint naming the variable to set.

The export path is untouched. resolveRunOtlpTarget still uses strict isAgentaIngest, so a run
aimed at a third-party collector never receives the refreshable platform credential.

Two diagnostics, because the 30 minutes this cost were spent finding the cause, not fixing it:

  • The stream line now separates the two empty cases: cred=DROPPED(endpoint-not-agenta-ingest)
    (a credential arrived and did not attribute) from cred=ABSENT(caller-sent-none). They have
    different fixes.
  • The runner warns at startup when AGENTA_API_URL is unset.

Docs

AGENTA_API_URL was documented only as a routing fallback for AGENTA_API_INTERNAL_URL, which is
what made "set the internal one and you are done" look correct. The configuration reference now
gives it its own row and states the distinction: the internal URL is an address, the public one
is an identity. Adds a troubleshooting entry on the remote-deploy page keyed to the exact error
text, and comments the variable in both Compose example env files.

Tests

  • tests/unit/platform-credential-attribution.test.ts (new, 9 cases): both directions of the
    attribution, the warn-once behavior, and publicApiBaseConfigured.
  • tests/unit/server.test.ts: the existing third-party-collector case never set AGENTA_API_URL,
    so it was asserting the protection in the state where the runner cannot decide. It now configures
    the public base, and a sibling case pins the self-hosted shape end to end at the server seam.

Full suite: 2338 passed. tsc --noEmit clean. Docs build clean.

Follow-up worth considering, not in this PR

The runner still cannot learn its own public base on its own. Having the API publish it, or having
the dispatcher mark the endpoint as platform-owned on the wire, would remove the configuration
requirement entirely. That is a design change and I did not want to slip it into a fix.

Related

Agenta-AI/agenta-skills#22 adds the same failure to the self-hosting troubleshooting skill, which
still applies to anyone on v0.114.0.

…nfigured

A self-hosted deployment on a public hostname failed every agent run with
"record log is unreadable; cannot rebuild the conversation", because the
runner was sending its API callbacks with no Authorization header at all.

platformCredentialForRequest forwards the run's credential to platform calls
only when it recognizes the run's OTLP trace endpoint as this deployment's own
API. That match is a string comparison against AGENTA_API_INTERNAL_URL,
AGENTA_API_URL and the cloud base. A dispatched run carries the endpoint the
API built from its PUBLIC base, so a runner configured with only its internal
hop matches nothing, drops the credential, and every call to /sessions/* is
rejected with 401. Records are never written and never read back, and the
history rebuild reports it far from the cause.

The attribution is only decidable once the runner knows the public base, so
arm the strict check only when it is configured. Without it the runner keeps
the credential (the behavior before the check existed) and says what to set;
with it, the third-party collector protection stays exactly as it was.

Also name the two empty-credential cases apart in the stream diagnostic, warn
at startup when AGENTA_API_URL is unset, and document the variable as an
identity input rather than only a routing fallback.
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Aug 25, 2026
@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
agenta-documentation Blocked Blocked Aug 25, 2026 4:01pm

Request Review

@mmabrouk

Copy link
Copy Markdown
Member Author

@coderabbitai review

@dosubot dosubot Bot added bug documentation Improvements or additions to documentation labels Aug 25, 2026
@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Review skipped

No new commits to review since the last review.

⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: d887afea-3ffd-4482-857b-c55e8e8c6a46

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • Documentation

    • Added troubleshooting guidance for unreadable agent-run logs, including configuration, recovery, and verification steps.
    • Clarified the roles of internal and public API URLs in runner callbacks, tracing, and credential attribution.
    • Documented required web URL configuration for Docker Compose deployments.
  • Bug Fixes

    • Improved credential handling for trace endpoints, retaining credentials for recognized Agenta endpoints and preventing unintended sharing with external endpoints.
    • Added clearer startup and diagnostic warnings for incomplete public API configuration.
    • Preserved authentication for self-hosted deployments using internal API configuration only.

Walkthrough

The runner now identifies platform ingest endpoints using configured API bases. It controls credential forwarding for non-ingest endpoints, adds startup and stream diagnostics, and documents AGENTA_API_URL and AGENTA_WEB_URL configuration.

Changes

Runner credential attribution

Layer / File(s) Summary
API base detection and configuration contract
docs/docs/self-host/reference/01-configuration.mdx, hosting/docker-compose/oss/env.oss.*.example, services/runner/src/tracing/otel.ts
The runner centralizes configured ingest bases and detects whether a public API base is configured. Documentation defines the related environment variables and callback behavior.
Credential attribution and startup diagnostics
services/runner/src/engines/sandbox_agent/runtime-policy.ts, services/runner/src/server.ts, docs/docs/self-host/deploy/01-deploy-remotely.mdx
The runner retains credentials for Agenta ingest endpoints, handles non-ingest endpoints based on public API configuration, deduplicates warnings, and reports credential states and missing configuration. Deployment documentation describes remediation steps.
Credential attribution validation
services/runner/tests/unit/platform-credential-attribution.test.ts, services/runner/tests/unit/server.test.ts
Tests cover endpoint matching, credential filtering, warning behavior, public API detection, collector handling, and self-hosted internal-hop authentication.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🔵 Low · up to 2f08b

The fix restores runner authentication when the public API base is unset, but the troubleshooting guidance is currently misleading and diagnostic logs may expose credentials embedded in OTLP URLs; merge is reasonable with explicit follow-up to correct the documentation and redact logged endpoints.

Sequence Diagram(s)

sequenceDiagram
  participant RunnerServer
  participant CredentialPolicy
  participant TraceEndpoint
  RunnerServer->>CredentialPolicy: Evaluate request endpoint and run credential
  CredentialPolicy->>CredentialPolicy: Match endpoint against configured ingest bases
  CredentialPolicy->>TraceEndpoint: Forward or remove credential
  RunnerServer-->>RunnerServer: Record credential diagnostics
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 77.78% which is sufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 5 files. (4 skipped: 4 u…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main fix: preserving the run credential when AGENTA_API_URL is not configured.
Description check ✅ Passed The description directly explains the self-hosted runner failure, the credential-attribution fix, diagnostics, documentation updates, tests, and validation results.
Full details: Docstring Coverage

Explanation

Docstring coverage is 77.78% which is sufficient. The required threshold is 60.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 9 functions across 5 files. (4 skipped: 4 unsupported.)

✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/runner-api-url-credential-attribution

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 6218d8d0-33a9-403d-ba6f-55421a502e41

📥 Commits

Reviewing files that changed from the base of the PR and between a09a0f0 and 2f08b8a.

📒 Files selected for processing (9)
  • docs/docs/self-host/deploy/01-deploy-remotely.mdx
  • docs/docs/self-host/reference/01-configuration.mdx
  • hosting/docker-compose/oss/env.oss.dev.example
  • hosting/docker-compose/oss/env.oss.gh.example
  • services/runner/src/engines/sandbox_agent/runtime-policy.ts
  • services/runner/src/server.ts
  • services/runner/src/tracing/otel.ts
  • services/runner/tests/unit/platform-credential-attribution.test.ts
  • services/runner/tests/unit/server.test.ts

Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review.

Comment on lines +233 to +261
### Agent Runs Fail With `record log is unreadable; cannot rebuild the conversation`

This applies if the deployment answers on a public hostname and agent runs fail while the rest of
the app works. Other symptoms of the same cause: an agent that forgets earlier turns, or runner logs
showing `cred=DROPPED(endpoint-not-agenta-ingest)` and `HTTP 401` on `/sessions/records/ingest`,
`/sessions/records/query`, and `/sessions/streams/heartbeat`.

**Cause:** The `runner` service has no `AGENTA_API_URL`. Each run carries the trace endpoint the API
built from its public base, for example `https://agenta.example.com/api/otlp/v1/traces`, while the
runner knows only its internal hop, `http://api:8000`. The runner cannot tell that endpoint apart
from a third-party OTLP collector, so it withholds the run's credential and every callback to the
API is rejected. Conversation history is never written and never read back.

**Solution:** Set `AGENTA_API_URL` to the same public API base the `api` and `services` containers
use, and recreate the runner:

```bash
docker compose up -d --force-recreate runner
```

Compose reads `AGENTA_API_URL` from the shell (or `--env-file`) when it builds the runner's
environment, not from a service's `env_file`. Setting it only in a file that is passed as `env_file`
reaches the API and services containers but not the runner. Confirm it landed:

```bash
docker compose exec runner printenv AGENTA_API_URL
```

Sessions that ran while this was broken keep the gaps in their history. New sessions are unaffected.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Update the troubleshooting cause for the new fallback behavior.

When AGENTA_API_URL is unset, platformCredentialForRequest keeps the credential for platform calls. It does not withhold it and cause the stated HTTP 401 failures. The runner warns because it cannot prevent a third-party collector credential from reaching platform calls. Describe a missing or mismatched configured public base as the cause only when strict attribution drops a credential.

Comment on lines +63 to +67
`[sessions] WARNING: trace endpoint ${endpoint} matches no configured Agenta ingest ` +
`base (${configuredIngestBases().join(", ")}), and AGENTA_API_URL is not set, so the ` +
`run credential cannot be attributed. Using it for platform calls anyway. Set ` +
`AGENTA_API_URL to this deployment's public api base (e.g. https://<host>/api) to ` +
`attribute it properly and to keep third-party collector credentials out of platform calls.`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Redact the trace endpoint before writing it to stderr.

These warnings log the raw endpoint. An OTLP endpoint can contain credentials in URL userinfo or query values. The runner then stores those credentials in its logs. Log a sanitized origin, or redact all URL credential-bearing components before interpolation.

Proposed fix
+function endpointForLog(endpoint: string): string {
+  try {
+    return new URL(endpoint).origin;
+  } catch {
+    return "<invalid endpoint>";
+  }
+}
+
- `[sessions] WARNING: trace endpoint ${endpoint} matches no configured Agenta ingest `
+ `[sessions] WARNING: trace endpoint ${endpointForLog(endpoint)} matches no configured Agenta ingest `

- `[sessions] trace endpoint ${endpoint} is not Agenta ingest `
+ `[sessions] trace endpoint ${endpointForLog(endpoint)} is not Agenta ingest `

Also applies to: 76-80

@coderabbitai

coderabbitai Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Already reviewed the last commit. Use @coderabbitai full review to rerun a review of the entire changeset.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

Copy link
Copy Markdown
Contributor

Railway Preview Environment

Preview URL https://gateway-pr-6281.up.railway.app/w
Project agenta-oss-clone-spike
Image tag pr-6281-7a92fce
Status Deployed
Railway logs Open logs
Workflow logs View workflow run
Updated at 2026-08-25T16:14:37.448Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug documentation Improvements or additions to documentation size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant