charmbracelet/crush · error

failed to initiate session agent processing: %w

Error message

failed to initiate session agent processing: %w

What it means

Thrown by Client.InitiateAgentProcessing in internal/client/proto.go when the HTTP POST to /workspaces/{id}/agent/init fails at the transport layer before a response is received. The wrapped error from c.post is returned, so it is always a connection, DNS, timeout, or context-cancellation problem. Called by InitCoderAgent and InitCoderAgentNonInteractive.

Source

Thrown at internal/client/proto.go:581

// AgentSummarizeSession requests a session summarization.
func (c *Client) AgentSummarizeSession(ctx context.Context, id string, sessionID string) error {
	rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/agent/sessions/%s/summarize", id, sessionID), nil, nil, nil)
	if err != nil {
		return fmt.Errorf("failed to summarize session: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return fmt.Errorf("failed to summarize session: status code %d", rsp.StatusCode)
	}
	return nil
}

// InitiateAgentProcessing triggers agent initialization on the server.
func (c *Client) InitiateAgentProcessing(ctx context.Context, id string, interactive bool) error {
	body := jsonBody(proto.AgentInitRequest{Interactive: interactive})
	rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/agent/init", id), nil, body, http.Header{"Content-Type": []string{"application/json"}})
	if err != nil {
		return fmt.Errorf("failed to initiate session agent processing: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return fmt.Errorf("failed to initiate session agent processing: status code %d", rsp.StatusCode)
	}
	return nil
}

// ListMessages retrieves all messages for a session as proto types.
func (c *Client) ListMessages(ctx context.Context, id string, sessionID string) ([]proto.Message, error) {
	rsp, err := c.get(ctx, fmt.Sprintf("/workspaces/%s/sessions/%s/messages", id, sessionID), nil, nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get messages: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("failed to get messages: status code %d", rsp.StatusCode)
	}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Check the wrapped error: context.DeadlineExceeded means retry with a longer timeout; connection-refused means start/check the server.
  2. Confirm the server address configured for the client matches the running crush server.
  3. Retry initialization after the server has fully started (add startup wait/health check).
  4. If the context was canceled, ensure nothing aborts the parent context prematurely.

Example fix

// before
err := client.InitiateAgentProcessing(ctx, wsID, true)
if err != nil {
    return err
}
// after: wait for the server then init with a deadline
if err := waitForServer(ctx, client); err != nil {
    return fmt.Errorf("server not ready: %w", err)
}
initCtx, cancel := context.WithTimeout(ctx, 15*time.Second)
defer cancel()
if err := client.InitiateAgentProcessing(initCtx, wsID, true); err != nil {
    return fmt.Errorf("agent init: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

// Wait for the server before initializing the agent
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, serverURL+"/healthz", nil)
rsp, err := http.DefaultClient.Do(req)
if err != nil || rsp.StatusCode != http.StatusOK {
    return errors.New("crush server not ready for agent init")
}

Type guard

func isInitTransportError(err error) bool {
    return errors.Is(err, context.DeadlineExceeded) ||
        errors.Is(err, context.Canceled) ||
        strings.Contains(err.Error(), "connection refused") ||
        strings.Contains(err.Error(), "no such host")
}

Try / catch

err := client.InitiateAgentProcessing(ctx, wsID, interactive)
if err != nil && isInitTransportError(err) {
    select {
    case <-time.After(2 * time.Second):
        return client.InitiateAgentProcessing(ctx, wsID, interactive)
    case <-ctx.Done():
        return ctx.Err()
    }
}

Prevention

When it happens

Trigger: Calling InitCoderAgent/InitCoderAgentNonInteractive when the server is unreachable, the workspace id is invalid at the URL level (though that would typically 404), the context is canceled, the connection is refused, or a TLS handshake fails.

Common situations: Crush server not started yet when the client boots; wrong host/port in client configuration; container network not up in dev environments; VPN or corporate proxy blocking the connection; very short context timeout expiring on a slow network.

Understand the failure class

Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/e9cbb397d564524a. Report an issue: GitHub.