henrygd/beszel · error

unexpected dest type for GetSmartData: %T

Error message

unexpected dest type for GetSmartData: %T

What it means

unmarshalLegacyResponse handles legacy (0.18.0) agent responses with typed fields. For GetSmartData it accepts only *map[string]smart.SmartData or *smart.SmartDataResponse as the destination. This error means the caller passed some other pointer type, so the legacy response cannot be copied into it.

Source

Thrown at internal/hub/transport/transport.go:106

		*d = *resp.String
		return nil
	case common.GetSmartData:
		switch d := dest.(type) {
		case *map[string]smart.SmartData:
			if resp.SmartData == nil {
				return errors.New("no SMART data in response")
			}
			*d = resp.SmartData
			return nil
		case *smart.SmartDataResponse:
			if resp.SmartData == nil {
				return errors.New("no SMART data in response")
			}
			d.Data = resp.SmartData
			d.Complete = resp.SmartComplete
			return nil
		default:
			return fmt.Errorf("unexpected dest type for GetSmartData: %T", dest)
		}
	case common.GetSystemdInfo:
		d, ok := dest.(*systemd.ServiceDetails)
		if !ok {
			return fmt.Errorf("unexpected dest type for GetSystemdInfo: %T", dest)
		}
		if resp.ServiceInfo == nil {
			return errors.New("no systemd info in response")
		}
		*d = resp.ServiceInfo
		return nil
	}
	return fmt.Errorf("unsupported action: %d", action)
}

View on GitHub (pinned to b38fb7dafa)

Solutions

  1. Change the dest argument to *map[string]smart.SmartData or *smart.SmartDataResponse for GetSmartData requests
  2. Upgrade the agent to 0.19+ so responses use the generic CBOR Data field, which unmarshals into any dest type
  3. Check the caller of UnmarshalResponse to ensure the dest type matches the action constant

Example fix

// before
var data smart.SmartData
err := t.Request(ctx, common.GetSmartData, nil, &data)
// after
var data map[string]smart.SmartData
err := t.Request(ctx, common.GetSmartData, nil, &data)
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := dest.(*map[string]smart.SmartData); !ok {
    if _, ok2 := dest.(*smart.SmartDataResponse); !ok2 {
        return fmt.Errorf("GetSmartData dest must be *map[string]smart.SmartData or *smart.SmartDataResponse, got %T", dest)
    }
}

Type guard

func isSmartDataDest(dest any) bool {
    switch dest.(type) {
    case *map[string]smart.SmartData, *smart.SmartDataResponse:
        return true
    }
    return false
}

Try / catch

if err := t.Request(ctx, common.GetSmartData, nil, dest); err != nil {
    var terr *transportError
    if strings.Contains(err.Error(), "unexpected dest type") { /* fix dest type */ }
    return err
}

Prevention

When it happens

Trigger: Calling Transport.Request (or UnmarshalResponse) with action common.GetSmartData while dest is a pointer to a type other than map[string]smart.SmartData or smart.SmartDataResponse, AND the agent response has an empty Data field (pre-0.19 agent), forcing the legacy path.

Common situations: Mixing hub/agent versions where legacy responses are still in play; refactoring code to use a custom SMART result struct; passing *smart.SmartData instead of *map[string]smart.SmartData.

Related errors


AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31). Data as JSON: /api/errors/92b65b2eefdc5ea4. Report an issue: GitHub.