Skip to content

bug: agent start/restart fails with "harness-config not found" — startAgent does not hydrate harness-config from Hub #1235

Description

@ghchinoy

Problem Description

When an agent whose harness configuration is registered on the Hub (and not on the broker's local filesystem) is restarted (via StartAgent), the broker fails with:

Failed to dispatch to runtime broker: runtime broker returned error 500: {"error":{"code":"runtime_error","message":"Failed to start agent: failed to find harness-config \"claude\": harness-config \"claude\" not found"}}

Even though:

  1. The harness configuration (claude, opencode, etc.) exists and is active on the Hub.
  2. Freshly created agents in the exact same project on the exact same broker start successfully.
  3. The stored appliedConfig on the failing agent is valid and contains the correct harnessConfigId and harnessConfigHash.

Root Cause Analysis

There is a structural divergence between the Create/Dispatch path and the Start/Restart path in the runtime broker:

  1. Create path (pkg/runtimebroker/handlers.go:675-694):

    • The Hub sends the full CreateAgentConfig, including HarnessConfigID and HarnessConfigHash.
    • buildStartContext invokes hydrateHarnessConfig (handlers.go:992), which fetches and caches the harness-config from the Hub using the ID/hash.
    • opts.HarnessConfigPath is populated on the context, so resolveHarnessConfigDir (pkg/agent/provision.go:411) resolves it successfully.
  2. Start/Restart path (pkg/runtimebroker/handlers.go:1291-1350):

    • startReq (handlers.go:1302) only receives HarnessConfig string (the name, e.g. "claude"), and is missing HarnessConfigID and HarnessConfigHash.
    • The hub-side dispatcher signature StartAgent (pkg/hub/httpdispatcher.go:65) only sends the harness name string, even though the Hub has access to agent.AppliedConfig.HarnessConfigID and agent.AppliedConfig.HarnessConfigHash.
    • Because ID and Hash are empty in cfg, hydrateHarnessConfig early-returns empty at handlers.go:993:
      if cfg == nil || (cfg.HarnessConfigID == "" && cfg.HarnessConfigHash == "") {
          return "", nil
      }
    • With opts.HarnessConfigPath unset, resolveHarnessConfigDir falls back to the on-disk search FindHarnessConfigDir (pkg/config/harness_config.go:105-150), searching only template/project/global local paths on the broker node. On brokers without a local ~/.scion/harness-configs/<name>/ directory, this returns harness-config %q not found (pkg/agent/provision.go:756).

Proposed Fix

  1. Broker Start Request (pkg/runtimebroker/handlers.go):

    • Add HarnessConfigID string json:"harnessConfigId,omitempty"andHarnessConfigHash string json:"harnessConfigHash,omitempty" to startReq (handlers.go:1302).
    • Populate cfg.HarnessConfigID and cfg.HarnessConfigHash when building CreateAgentConfig in startAgent (handlers.go:1339).
  2. Hub Client & Dispatcher Transport (pkg/hub/httpdispatcher.go, controlchannel_client.go, brokerclient.go):

    • Update StartAgent signatures and payloads to pass harnessConfigID and harnessConfigHash.
    • In httpdispatcher.go, read agent.AppliedConfig.HarnessConfigID and agent.AppliedConfig.HarnessConfigHash when calling StartAgent.

A PR with this fix and regression tests is in preparation.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions