{"record":{"id":"bbc7d580efbee94f","repo":"derailed/k9s","slug":"expected-workloadres-but-got-t","errorCode":null,"errorMessage":"expected WorkloadRes but got %T","messagePattern":"expected WorkloadRes but got %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/render/workload.go","lineNumber":59,"sourceCode":"\t\tstatus := strings.TrimSpace(re.Row.Fields[idx])\n\t\tif status == \"DEGRADED\" {\n\t\t\tc = model1.PendingColor\n\t\t}\n\n\t\treturn c\n\t}\n}\n\n// Header returns a header rbw.\nfunc (Workload) Header(string) model1.Header {\n\treturn defaultWKHeader\n}\n\n// Render renders a K8s resource to screen.\nfunc (Workload) Render(o any, _ string, r *model1.Row) error {\n\tres, ok := o.(*WorkloadRes)\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected WorkloadRes but got %T\", o)\n\t}\n\n\tr.ID = fmt.Sprintf(\"%s|%s|%s\", res.Row.Cells[0].(string), res.Row.Cells[1].(string), res.Row.Cells[2].(string))\n\tr.Fields = model1.Fields{\n\t\tres.Row.Cells[0].(string),\n\t\tres.Row.Cells[1].(string),\n\t\tres.Row.Cells[2].(string),\n\t\tres.Row.Cells[3].(string),\n\t\tres.Row.Cells[4].(string),\n\t\tres.Row.Cells[5].(string),\n\t\tToAge(res.Row.Cells[6].(metav1.Time)),\n\t}\n\n\treturn nil\n}\n\ntype WorkloadRes struct {\n\tRow metav1.TableRow","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/render/workload.go#L41-L77","documentation":"The Workload renderer expects a *WorkloadRes — an internal wrapper that bundles a metav1.TableRow plus container info for workload views (pods and their owning workloads). The assertion failed because the caller passed a bare metav1.TableRow, unstructured object, or other type. This is an internal contract violation between the workload view and its data assembler.","triggerScenarios":"Calling Workload.Render(o, _, r) with a raw *unstructured.Unstructured or metav1.TableRow instead of the WorkloadRes wrapper built by the workload view's data path. Happens when a custom viewer reuses the Workload renderer without constructing WorkloadRes{Row: ..., Containers: ...}.","commonSituations":"Custom viewers that borrow the workload header/render logic; refactoring that drops the wrapper and passes the inner row directly; tests calling Render with simplified fixtures.","solutions":["Construct the wrapper before rendering: res := &WorkloadRes{Row: row, Containers: specs} then pass res to Render.","If you only have a table row, use the Table renderer instead of Workload.","Guard the cell casts too: after the type check, Render indexes Cells[0..6] with hard .(string) casts, so rows with fewer/different cells will panic — ensure the producer always emits 7 cells in the expected order."],"exampleFix":"// before\nerr := wk.Render(&metav1.TableRow{Cells: cells}, ns, r)\n\n// after\nerr := wk.Render(&WorkloadRes{Row: metav1.TableRow{Cells: cells}}, ns, r)","handlingStrategy":"type-guard","validationCode":"res, ok := o.(*WorkloadRes)\nif !ok {\n    return fmt.Errorf(\"workload renderer needs *WorkloadRes, got %T\", o)\n}\n_ = res","typeGuard":"func asWorkloadRes(o any) (*WorkloadRes, bool) {\n    res, ok := o.(*WorkloadRes)\n    return res, ok\n}","tryCatchPattern":"if err := wk.Render(obj, ns, r); err != nil {\n    if strings.Contains(err.Error(), \"expected WorkloadRes\") {\n    slog.Error(\"workload renderer misuse\", \"actualType\", fmt.Sprintf(\"%T\", obj))\n    }\n}","preventionTips":["Build WorkloadRes only in the workload view's data path; never hand-roll calls to Workload.Render.","Validate row cell count/types (7 cells, strings + metav1.Time) before Render to avoid the subsequent hard casts panicking.","Cover renderer contracts with unit tests per registered viewer."],"tags":["go","kubernetes","type-assertion","workload","rendering"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}