derailed/k9s · error
expecting Job resource
Error message
expecting Job resource
What it means
Job.List fetches all Jobs in a namespace via the generic resource list, converts each *unstructured.Unstructured into batchv1.Job, and filters by owner reference against the controller path carried in ctx (internal.KeyPath) for the CronJob detail view (internal/dao/job.go:58). If any listed Job fails conversion, the sentinel 'expecting Job resource' aborts the whole listing and the underlying converter error is dropped.
Source
Thrown at internal/dao/job.go:58
return render.ExtractImages(&job.Spec.Template.Spec), nil
}
// List returns a collection of resources.
func (j *Job) List(ctx context.Context, ns string) ([]runtime.Object, error) {
oo, err := j.Resource.List(ctx, ns)
if err != nil {
return nil, err
}
ctrl, _ := ctx.Value(internal.KeyPath).(string)
_, n := client.Namespaced(ctrl)
ll := make([]runtime.Object, 0, 10)
for _, o := range oo {
var j batchv1.Job
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &j)
if err != nil {
return nil, errors.New("expecting Job resource")
}
if n == "" {
ll = append(ll, o)
continue
}
for _, r := range j.OwnerReferences {
if r.Name == n {
ll = append(ll, o)
}
}
}
return ll, nil
}
// TailLogs tail logs for all pods represented by this Job.
func (j *Job) TailLogs(ctx context.Context, opts *LogOptions) ([]LogChan, error) {View on GitHub (pinned to 2d3ccc6ba2)
Solutions
- Audit the namespace: kubectl get jobs.batch -n <ns> -o yaml and look for unexpected or mistyped fields; fix offending manifests.
- Upgrade k9s so its vendored k8s.io/* versions match the cluster.
- Verify jobs.batch is served by the core apiserver and not shadowed.
- Restart k9s to rebuild informer caches.
- Patch the loop to skip and log unparsable Jobs instead of failing the list.
Example fix
// before
var j batchv1.Job
err = runtime.DefaultUnstructuredConverter.FromUnstructured(o.(*unstructured.Unstructured).Object, &j)
if err != nil {
return nil, errors.New("expecting Job resource")
}
// after
u, ok := o.(*unstructured.Unstructured)
if !ok {
continue
}
var j batchv1.Job
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &j); err != nil {
slog.Warn("skip unparsable job", "fqn", client.FQN(u.GetNamespace(), u.GetName()), "err", err)
continue
} Defensive patterns
Strategy: try-catch
Validate before calling
for _, o := range oo {
u, ok := o.(*unstructured.Unstructured)
if !ok || u.GroupVersionKind().Kind != "Job" {
continue
}
// safe to convert below
} Type guard
func isJob(o runtime.Object) bool {
u, ok := o.(*unstructured.Unstructured)
return ok && u.GroupVersionKind().Kind == "Job" && u.GroupVersionKind().Group == "batch"
} Try / catch
if err := runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, &j); err != nil {
slog.Warn("skip unparsable job", "fqn", fqn, "err", err)
continue // listing must survive one bad object
} Prevention
- Design list paths to skip unparsable objects and log them, never abort the browser.
- Wrap conversion errors with %w including the object name.
- Clean up legacy Jobs mutated by old controllers when upgrading clusters.
- Keep k9s's k8s.io/api in sync with the cluster.
When it happens
Trigger: Browsing jobs (or opening a CronJob's owned-jobs list) in a namespace where at least one stored Job object cannot convert to the compiled batchv1.Job struct — k9s/cluster version skew, an aggregated API shadowing jobs.batch, or jobs patched with out-of-schema fields. A single bad Job breaks the entire job browser for that namespace.
Common situations: k9s builds with older k8s.io/api against newer clusters where job spec/status fields changed; namespaces with Jobs created by legacy CRD controllers; GitOps force-applied legacy job manifests.
Related errors
- expecting cronjob resource
- expecting Deployment resource
- expecting DaemonSet resource
- expecting a job resource
- expecting ServiceAccount resource
AI-assisted analysis of derailed/k9s@2d3ccc6ba2 (2026-08-15).
Data as JSON: /api/errors/dda11988de66d372.
Report an issue: GitHub.