Skip to content

Kernel provider: KERNEL_PROFILE_NAME always fails with HTTP 400 (profile sent as string, API expects object) #1473

Description

@boatri

Summary

With the Kernel provider, setting KERNEL_PROFILE_NAME makes every browser open fail with HTTP 400. connect_kernel() serializes the create-browser profile field as a bare string, but Kernel's API expects an object ({ name, save_changes }). The request is rejected at JSON-decode time, so no browser is ever created.

Version

agent-browser 0.29.1 (current main). This has been broken since the Kernel provider was added (#200) — connect_kernel has always sent profile as a string.

Reproduction

export AGENT_BROWSER_PROVIDER=kernel
export KERNEL_API_KEY=...
export KERNEL_PROFILE_NAME=anything        # any non-empty value
agent-browser --session t open https://example.com

Actual:

✗ Kernel API error (400): can't decode JSON body: json: cannot unmarshal
  string into Go struct field BrowserRequest.profile of type map[string]json.RawMessage

Expected: the browser opens using the named profile (and, per the docs below, persists cookies/logins back to it on close).

Root cause

cli/src/native/providers.rsconnect_kernel():

body.as_object_mut()
    .unwrap()
    .insert("profile".to_string(), json!(profile)); // profile: String

Kernel's POST /browsers expects profile as an object, matching the @onkernel/sdk BrowserProfile type:

interface BrowserProfile { id?: string; name?: string; save_changes?: boolean }

Evidence (string vs object, same pre-existing profile)

Posting directly to POST /browsers with an existing profile, varying only the profile field:

profile value Status Body
"my-profile" (string) 400 cannot unmarshal string into ... profile of type map[string]json.RawMessage
{ "name": "my-profile", "save_changes": true } (object) 200 browser created

The string is rejected at decode time regardless of whether the profile exists, so this is purely a serialization mismatch.

Note on persistence (save_changes)

The README and Kernel provider docs state that profile data is "automatically saved back to the profile when the browser session ends." That requires save_changes: true in the object — the SDK's own default is false, which would load the profile but silently never persist. So the object should be sent with save_changes: true to make the documented behavior actually work.

I have a fix ready (send { name, save_changes: true }, plus unit tests) and will open a PR referencing this issue.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions