{"record":{"id":"cbcd1be18b582cd7","repo":"derailed/k9s","slug":"expected-tablerow-but-got-t","errorCode":null,"errorMessage":"expected TableRow, but got %T","messagePattern":"expected TableRow, but got %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/render/table.go","lineNumber":90,"sourceCode":"\t\tif c.Name == ageTableCol {\n\t\t\tt.setAgeIndex(i)\n\t\t\tcontinue\n\t\t}\n\t\ttimeCol := ageCols.Has(c.Name)\n\t\th = append(h, model1.HeaderColumn{Name: strings.ToUpper(c.Name), Attrs: model1.Attrs{Time: timeCol, Wide: c.Priority > 0}})\n\t}\n\tif t.getAgeIndex() > 0 {\n\t\th = append(h, model1.HeaderColumn{Name: \"AGE\", Attrs: model1.Attrs{Time: true}})\n\t}\n\n\treturn h\n}\n\n// Render renders a K8s resource to screen.\nfunc (t *Table) Render(o any, ns string, r *model1.Row) error {\n\trow, ok := o.(metav1.TableRow)\n\tif !ok {\n\t\treturn fmt.Errorf(\"expected TableRow, but got %T\", o)\n\t}\n\tif err := t.defaultRow(&row, ns, r); err != nil {\n\t\treturn err\n\t}\n\tif t.specs.isEmpty() {\n\t\treturn nil\n\t}\n\n\tobj := row.Object.Object\n\tif obj != nil {\n\t\tobj = obj.DeepCopyObject()\n\t}\n\tcols, err := t.specs.realize(obj, t.defaultHeader(), r)\n\tcols.hydrateRow(r)\n\n\treturn err\n}\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/render/table.go#L72-L108","documentation":"The metav1.Table renderer requires the object to be a metav1.TableRow value type (not a pointer, not an unstructured). The assertion `o.(metav1.TableRow)` failed, so the pipeline delivered *unstructured.Unstructured, a typed object, or a *metav1.TableRow pointer. It indicates the wrong renderer is wired to the data source, or the row was double-wrapped.","triggerScenarios":"Calling Table.Render(o, ns, r) where o is *unstructured.Unstructured (informal cache data), a typed pod/deployment struct, or *metav1.TableRow (pointer instead of value: %T prints *v1.TableRow). Also triggered when a custom viewer forwards the wrong element of a metav1.Table.Rows slice.","commonSituations":"Mixing informer-based browsing with table-based renderers; a decorator dereferencing level mismatch (passing &row instead of row); client-go upgrades where watch payloads change representation.","solutions":["Pass the row by value: t.Render(row, ns, r) with row of type metav1.TableRow, dereferencing any pointer (*row).","If data is unstructured, convert it to a TableRow with the right cells or use the unstructured-capable renderer (Service/Workload path).","Check which renderer the view registered for the GVR and align the data source (Table vs informer) with it."],"exampleFix":"// before\nerr := tbl.Render(&row, ns, r)\n\n// after\nerr := tbl.Render(row, ns, r)","handlingStrategy":"type-guard","validationCode":"row, ok := o.(metav1.TableRow)\nif !ok {\n    if ptr, isPtr := o.(*metav1.TableRow); isPtr {\n        row, ok = *ptr, true\n    }\n}\nif !ok { return fmt.Errorf(\"table renderer needs a TableRow, got %T\", o) }\nerr := tbl.Render(row, ns, r)","typeGuard":"func asTableRow(o any) (metav1.TableRow, bool) {\n    switch v := o.(type) {\n    case metav1.TableRow:\n        return v, true\n    case *metav1.TableRow:\n        return *v, true\n    default:\n        return metav1.TableRow{}, false\n    }\n}","tryCatchPattern":"if err := tbl.Render(obj, ns, r); err != nil && strings.Contains(err.Error(), \"expected TableRow\") {\n    slog.Error(\"table renderer got wrong type\", \"actualType\", fmt.Sprintf(\"%T\", obj))\n}","preventionTips":["Pass metav1.TableRow by value, never a pointer.","Keep one renderer per data source: Table renderer for metav1.Table pipelines, unstructured renderers for informer pipelines.","Assert types in view tests with the same objects production feeds them."],"tags":["go","kubernetes","type-assertion","metav1-table","rendering"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}