{"record":{"id":"4f0b1e16f2f1e4a4","repo":"henrygd/beszel","slug":"unexpected-dest-type-for-getcontainerinfo-t","errorCode":null,"errorMessage":"unexpected dest type for GetContainerInfo: %T","messagePattern":"unexpected dest type for GetContainerInfo: %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/hub/transport/transport.go","lineNumber":83,"sourceCode":"\t\tif resp.Fingerprint == nil {\n\t\t\treturn errors.New(\"no fingerprint in response\")\n\t\t}\n\t\t*d = *resp.Fingerprint\n\t\treturn nil\n\tcase common.GetContainerLogs:\n\t\td, ok := dest.(*string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected dest type for GetContainerLogs: %T\", dest)\n\t\t}\n\t\tif resp.String == nil {\n\t\t\treturn errors.New(\"no logs in response\")\n\t\t}\n\t\t*d = *resp.String\n\t\treturn nil\n\tcase common.GetContainerInfo:\n\t\td, ok := dest.(*string)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected dest type for GetContainerInfo: %T\", dest)\n\t\t}\n\t\tif resp.String == nil {\n\t\t\treturn errors.New(\"no info in response\")\n\t\t}\n\t\t*d = *resp.String\n\t\treturn nil\n\tcase common.GetSmartData:\n\t\tswitch d := dest.(type) {\n\t\tcase *map[string]smart.SmartData:\n\t\t\tif resp.SmartData == nil {\n\t\t\t\treturn errors.New(\"no SMART data in response\")\n\t\t\t}\n\t\t\t*d = resp.SmartData\n\t\t\treturn nil\n\t\tcase *smart.SmartDataResponse:\n\t\t\tif resp.SmartData == nil {\n\t\t\t\treturn errors.New(\"no SMART data in response\")\n\t\t\t}","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/henrygd/beszel/blob/b38fb7dafa60812cc22e6a84ce313e94f1ce0a32/internal/hub/transport/transport.go#L65-L101","documentation":"For legacy responses, unmarshalLegacyResponse requires dest to be *string when action is common.GetContainerInfo; otherwise it returns 'unexpected dest type for GetContainerInfo: %T'. The container info string arrives in the typed resp.String field and is copied only into a *string target.","triggerScenarios":"Calling Request with GetContainerInfo and a dest other than *string while the response's generic Data field is empty (legacy 0.18.x agent), forcing the legacy branch.","commonSituations":"Call sites changed to a struct dest (e.g. docker inspect struct) incompatible with the legacy path; helper functions parameterized with the wrong type.","solutions":["Pass a *string as dest for common.GetContainerInfo","Upgrade the agent so generic Data responses are used and dest can match the richer schema","Audit GetContainerInfo call sites to keep action/dest pairs consistent"],"exampleFix":"// before\nvar info struct{ ID string `json:\"id\"` }\nerr := transport.Request(ctx, common.GetContainerInfo, infoReq, &info)\n// after\nvar info string\nerr := transport.Request(ctx, common.GetContainerInfo, infoReq, &info)","handlingStrategy":"type-guard","validationCode":"if action == common.GetContainerInfo {\n    if _, ok := dest.(*string); !ok {\n        return fmt.Errorf(\"GetContainerInfo requires *string, got %T\", dest)\n    }\n}","typeGuard":"func isStringPtr(dest any) bool {\n    _, ok := dest.(*string)\n    return ok\n}","tryCatchPattern":"err := t.Request(ctx, common.GetContainerInfo, req, dest)\nif err != nil && strings.Contains(err.Error(), \"unexpected dest type for GetContainerInfo\") {\n    return fmt.Errorf(\"caller bug: wrong dest type for GetContainerInfo: %w\", err)\n}","preventionTips":["Always pass *string for GetContainerInfo","Use per-action typed wrappers to catch mismatches at compile time","Keep hub/agent versions aligned to prefer the generic Data path","Audit call sites after any refactor of container-info handling"],"tags":["type-mismatch","legacy-compat","programming-error"],"backgroundTag":"unexpected-response-type","analyzedSha":"b38fb7dafa60812cc22e6a84ce313e94f1ce0a32","analyzedAt":"2026-08-31T15:10:10.149Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}