charmbracelet/crush · error

failed to remove config field: %w

Error message

failed to remove config field: %w

What it means

RemoveConfigField wraps a transport-level failure of the POST to /workspaces/{id}/config/remove. The removal request never completed.

Source

Thrown at internal/client/config.go:38

	}{Scope: scope, Key: key, Value: value}), http.Header{"Content-Type": []string{"application/json"}})
	if err != nil {
		return fmt.Errorf("failed to set config field: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return fmt.Errorf("failed to set config field: status code %d", rsp.StatusCode)
	}
	return nil
}

// RemoveConfigField removes a config key on the server.
func (c *Client) RemoveConfigField(ctx context.Context, id string, scope config.Scope, key string) error {
	rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/config/remove", id), nil, jsonBody(struct {
		Scope config.Scope `json:"scope"`
		Key   string       `json:"key"`
	}{Scope: scope, Key: key}), http.Header{"Content-Type": []string{"application/json"}})
	if err != nil {
		return fmt.Errorf("failed to remove config field: %w", err)
	}
	defer rsp.Body.Close()
	if rsp.StatusCode != http.StatusOK {
		return fmt.Errorf("failed to remove config field: status code %d", rsp.StatusCode)
	}
	return nil
}

// UpdatePreferredModel updates the preferred model on the server.
func (c *Client) UpdatePreferredModel(ctx context.Context, id string, scope config.Scope, modelType config.SelectedModelType, model config.SelectedModel) error {
	rsp, err := c.post(ctx, fmt.Sprintf("/workspaces/%s/config/model", id), nil, jsonBody(struct {
		Scope     config.Scope             `json:"scope"`
		ModelType config.SelectedModelType `json:"model_type"`
		Model     config.SelectedModel     `json:"model"`
	}{Scope: scope, ModelType: modelType, Model: model}), http.Header{"Content-Type": []string{"application/json"}})
	if err != nil {
		return fmt.Errorf("failed to update preferred model: %w", err)
	}

View on GitHub (pinned to 7944b8e522)

Solutions

  1. During logout, treat this as non-fatal if the key will be cleared anyway
  2. Verify server connectivity and retry the removal
  3. Check the wrapped error to distinguish connection refused from other causes

Example fix

// before
if err := c.RemoveConfigField(ctx, id, scope, key); err != nil {
    return err
}
// after
if err := c.RemoveConfigField(ctx, id, scope, key); err != nil {
    log.Warn("failed to remove config field during logout", "err", err)
    // continue logout; do not block on cleanup
}
Defensive patterns

Strategy: fallback

Validate before calling

// During logout, check server liveness first
if _, err := os.Stat(socketPath); err != nil {
    return nil // server gone; nothing to remove
}

Try / catch

if err := c.RemoveConfigField(ctx, id, scope, key); err != nil {
    log.Warn("config removal failed, continuing logout", "err", err)
}

Prevention

When it happens

Trigger: c.post returns an error (connection failure, canceled context) when removing a config key; called by logoutHyper and logoutCopilot.

Common situations: During logout flows the server has already exited, so the connection fails; socket/port stale after a crash.

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/30f34eb4ff6baee8. Report an issue: GitHub.