Skip to content

frontend: crd: Guard against incomplete CRD spec in makeCRClass#5717

Open
WasThatRudy wants to merge 1 commit into
kubernetes-sigs:mainfrom
WasThatRudy:fix/crd-incomplete-spec-guards
Open

frontend: crd: Guard against incomplete CRD spec in makeCRClass#5717
WasThatRudy wants to merge 1 commit into
kubernetes-sigs:mainfrom
WasThatRudy:fix/crd-incomplete-spec-guards

Conversation

@WasThatRudy
Copy link
Copy Markdown
Contributor

@WasThatRudy WasThatRudy commented May 17, 2026

Summary

CustomResourceDefinition.makeCRClass, getMainAPIGroup, the plural getter, and isNamespacedScope all assumed this.spec, this.spec.versions, and this.spec.names were fully populated. When a CRD reaches one of these methods with a partial spec (a transient watch update or in-flight refetch can leave the field undefined for a moment), the nested access throws and the whole dashboard view crashes with TypeError: Cannot read properties of undefined (reading 'names') or (reading 'versions').

Related Issue

Fixes #4824.

Changes

frontend/src/lib/k8s/crdSpec.ts (new)

Pure-helper module extracted so the validation and version-selection logic can be unit tested without instantiating CustomResourceDefinition (which transitively triggers a circular import in lib/k8s/index.ts).

  • CRDSpecLike, CRDVersionLike, UsableCRDVersion interfaces describing the subset of the CRD schema the helpers depend on.
  • validateCRDSpec(spec) returns { ok, missing, usableVersions }. ok=false lists the missing required fields. usableVersions is the subset filtered to name && served === true.
  • selectMainAPIGroup(spec) returns [group, version, plural] or null. Prefers the storage version, falls back to the first served version, honours the v1beta1 spec.version single-version shape only when spec.versions[] is empty or when spec.version matches a served entry.

Both helpers are pure: no logging, no module-level state, safe to call from render paths.

frontend/src/lib/k8s/crd.ts

  • makeCRClass() keeps its original non-nullable signature (typeof KubeObject<KubeCRD>). Throws with a clear error listing the missing fields when the spec is incomplete, so plugin/library consumers see the same kind of failure as before Crash Report: Cannot read properties of undefined (reading 'names') #4824 with a more diagnostic message and a pointer to the new API.
  • makeCRClassOrNull() (new) returns typeof KubeObject<KubeCRD> | null for callers that want to render a non-error UI state for partially-loaded or malformed CRDs. Pure: no console side effects, safe inside useMemo. names.singular is intentionally not required (Kubernetes server defaults it from kind); when absent we fall back to spec.names.kind.toLowerCase().
  • getMainAPIGroup() keeps its original non-nullable signature, returning ['', '', ''] for incomplete specs to preserve backward compatibility.
  • getMainAPIGroupOrNull() (new) returns the same tuple or null for callers that need to distinguish "incomplete CRD" from genuinely-empty fields.
  • get plural() uses optional chaining and returns '' when the spec is incomplete; return type stays string for backward compatibility. Callers needing an explicit signal should use getMainAPIGroupOrNull().
  • get isNamespacedScope() uses optional chaining on spec.scope.
  • makeCustomResourceClass.getBaseObject() consumes getMainAPIGroupOrNull() and falls back to apiInfoArgs[0] when the spec is incomplete.

Call sites updated to use the new nullable variants

File Behaviour
frontend/src/components/crd/CustomResourceDetails.tsx Split into outer (CRClass null = Empty with "incomplete spec" message) + inner that takes a non-null CRClass prop. getExtraColumns guards spec?.versions?.find.
frontend/src/components/crd/CustomResourceInstancesList.tsx Filters incomplete CRDs at the parent (CrInstanceList) into a classified list, sorts by ${cluster}/${uid||name} so the child's per-entry useList hook order is stable across refetches. remountKey is a content-addressed fingerprint (two independent 32-bit hashes concatenated, no BigInt literals). When all CRDs are unusable, renders a non-loading Empty so users aren't stuck on an indefinite spinner.
frontend/src/components/crd/CustomResourceList.tsx Split into outer (CRClass + apiGroup null = Empty with "incomplete spec" message) + inner that takes them as non-null props. title falls back to crd.metadata.name when kind is missing.
frontend/src/components/resourceMap/sources/definitions/sources.tsx Early continue when spec?.names?.kind is missing; null guards getMainAPIGroupOrNull() and makeCRClassOrNull().
frontend/src/components/resourceMap/sources/definitions/relations.tsx flatMap drops CRDs whose makeCRClassOrNull() is null.
frontend/src/components/resourceMap/sources/GraphSources.tsx makeKubeObjectNode null guards getMainAPIGroupOrNull() before destructuring.

TypeScript enforces the null handling at compile time on the *OrNull paths; tsc fails if any consumer of the new APIs forgets to handle null.

Tests

  • frontend/src/lib/k8s/crd.test.ts (new): 16 unit tests covering selectMainAPIGroup (storage-vs-served precedence, served filtering, v1beta1 spec.version fallback, mismatched spec.version, all-empty inputs) and validateCRDSpec (complete vs incomplete spec, missing-field reporting, usable-version filter, v1beta1 shape, undefined input).
  • frontend/src/components/crd/CustomResourceDetails.test.tsx: asserts the empty-state message renders when makeCRClassOrNull() returns null.
  • frontend/src/components/crd/CustomResourceInstancesList.test.tsx: asserts CRDs with null makeCRClassOrNull() are filtered out without crashing.

Translations

The two new user-facing strings ("This CustomResourceDefinition has an incomplete spec." and "No CustomResourceDefinitions with usable specs were found.") are translated in all 15 non-English locales (ar, de, es, fr, he, hi, it, ja, ko, pt, ru, ta, ur, zh, zh-tw). CustomResourceDefinition is left untranslated since it's a Kubernetes API proper noun.

Steps to Test

  1. cd frontend && npm install
  2. npm run lint: passes.
  3. npm run tsc: passes.
  4. npx vitest run src/components/crd src/lib/k8s/crd.test.ts: 25 tests pass.
  5. Manual repro of the reported crash:
    • Open the resource map or a CRD details view while a CRD's spec hasn't fully arrived.
    • Before this PR: dashboard crashes with Cannot read properties of undefined (reading 'names') or (reading 'versions') and the whole view goes white.
    • After this PR: the dashboard stays mounted, the incomplete CRD is skipped (in list/map paths) or shown as an empty state (in detail/list paths) describing the incomplete spec.

Screenshots

N/A. The fix prevents a crash; visible effect is the absence of one.

Notes for the Reviewer

  • DCO sign-off applied in the commit.
  • Backward compatibility: makeCRClass() and getMainAPIGroup() keep their pre-existing non-nullable signatures so existing plugin consumers compile unchanged. New *OrNull() variants are the recommended path for code that needs to handle the incomplete-spec state without throwing.
  • Defensive-fix scope: this is a consumer-boundary fix. The deeper question of why a CRD reaches these methods with a partial spec (a websocket ADDED event delivering an incomplete payload? an early useMemo evaluation? a query-cache eviction?) needs reproduction and is left as a follow-up.
  • Independent of frontend: api/v2: Include class identity in kube object query keys #5716.

@k8s-ci-robot k8s-ci-robot requested review from illume and yolossn May 17, 2026 13:40
@k8s-ci-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: WasThatRudy
Once this PR has been reviewed and has the lgtm label, please assign yolossn for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@k8s-ci-robot k8s-ci-robot added size/M Denotes a PR that changes 30-99 lines, ignoring generated files. cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. labels May 17, 2026
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 3895192 to 882f9fc Compare May 17, 2026 14:00
@WasThatRudy
Copy link
Copy Markdown
Contributor Author

Pushed 882f9fc53 to fix the ci-lint failure. The original [item, error] = CRClass ? CRClass.useGet(...) : [null, null] violated react-hooks/rules-of-hooks because useGet is itself a hook and was being called conditionally. Local npm run lint passed because the project lint allows warnings, but ci-lint runs with --max-warnings 0 and rightly flagged it.

Refactored CustomResourceDetailsRenderer into two components: the outer one returns the Loader when CRClass is null, the inner CustomResourceDetailsItem receives a non-null CRClass as a prop and calls useGet unconditionally. Standard React pattern for hook-on-conditional-class scenarios. No behaviour change; tests still 7/7 in src/components/crd.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens CRD handling in the frontend by making CustomResourceDefinition.makeCRClass() and related helpers resilient to transient/incomplete CRD specs (e.g., partial watch updates), preventing dashboard crashes like Cannot read properties of undefined (reading 'names'|'versions').

Changes:

  • Made CustomResourceDefinition.makeCRClass() return null (with a warning) instead of throwing when required CRD spec fields are missing, and added safer defaults to getMainAPIGroup(), plural, and isNamespacedScope.
  • Updated CRD consumers (CRD details/list/resource map) to handle a nullable CR class by skipping incomplete CRDs or showing a loader.
  • Adjusted typing at call sites to enforce null-handling via TypeScript.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
frontend/src/lib/k8s/crd.ts Adds defensive guards/defaults and makes makeCRClass() nullable to avoid crashes on partial CRD specs.
frontend/src/components/crd/CustomResourceDetails.tsx Shows a loader when makeCRClass() returns null and avoids calling useGet without a valid class.
frontend/src/components/crd/CustomResourceInstancesList.tsx Skips CRDs with incomplete specs when building per-CRD list queries.
frontend/src/components/crd/CustomResourceList.tsx Widens CRClass type to `...
frontend/src/components/resourceMap/sources/definitions/sources.tsx Skips creating graph sources for CRDs whose makeCRClass() returns null.
frontend/src/components/resourceMap/sources/definitions/relations.tsx Drops owner relations for CRDs that can’t build a class due to incomplete spec.
Comments suppressed due to low confidence (2)

frontend/src/components/crd/CustomResourceInstancesList.tsx:38

  • Switching from map to flatMap here breaks positional alignment between queries/dataClassCrds and the original crds array. Later code indexes crds[i] / crds[index] when iterating over queries, which will now refer to the wrong CRD (or the wrong name in the warning) whenever any CRD is skipped. Use the filtered dataClassCrds[i].crd instead of crds[i], or avoid filtering before building these index-based mappings.
  const dataClassCrds = crds.flatMap(crd => {
    const crdClass = crd.makeCRClass();
    if (!crdClass) {
      // CRD with incomplete spec; skip rather than crash on useList (#4824).
      return [];
    }
    const data = crdClass.useList({ cluster: crd.cluster, namespace: namespaces });
    return [{ data, crdClass, crd }];
  });

frontend/src/components/crd/CustomResourceInstancesList.tsx:38

  • There are existing component tests for this file, but none cover the new “skip incomplete CRD” behavior introduced by returning [] when makeCRClass() returns null. Adding a test case with one CRD returning null would validate both the skip behavior and that the warning/error mapping still refers to the correct CRD.
  const dataClassCrds = crds.flatMap(crd => {
    const crdClass = crd.makeCRClass();
    if (!crdClass) {
      // CRD with incomplete spec; skip rather than crash on useList (#4824).
      return [];
    }
    const data = crdClass.useList({ cluster: crd.cluster, namespace: namespaces });
    return [{ data, crdClass, crd }];
  });

Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceDetails.tsx Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 882f9fc to 121f373 Compare May 17, 2026 19:06
@k8s-ci-robot k8s-ci-robot added size/L Denotes a PR that changes 100-499 lines, ignoring generated files. and removed size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels May 17, 2026
@WasThatRudy
Copy link
Copy Markdown
Contributor Author

Pushed 121f37366 addressing @copilot's review:

  1. Hook count instability in CustomResourceInstancesList.tsx — fair catch. The original flatMap over crds conditionally called useList, so a CRD transitioning from incomplete to complete spec would change the number of hook calls between renders and trigger React's "Rendered more/fewer hooks than expected" error. Refactored: the parent CrInstanceList now classifies CRDs (filters out the ones with null makeCRClass) and passes a ClassifiedCrd[] to CrInstancesView. The child component's useList count is now stable per mount, and the key derived from classified-CRD names triggers a clean remount on transition.

  2. spec.group can be undefined at runtime — agreed, defaulting it to '' in makeCRClass's apiInfo construction so a partial spec with present versions/names but missing group still produces a usable class.

  3. Test coverage for the null branch — added it('skips CRDs whose makeCRClass returns null without crashing (#4824)') to CustomResourceInstancesList.test.tsx. The test passes an incomplete-CRD mock alongside a healthy one; the rendered row count and absence of warning Alert confirm the null-handling. 8/8 tests pass in src/components/crd. A crd.test.ts would still be ideal for testing makeCRClass directly but is blocked by the circular-import problem in lib/k8s/ I noted in the original PR description.

@WasThatRudy
Copy link
Copy Markdown
Contributor Author

cc @illume — both @copilot comments addressed in 121f37366 (hook-count fix by filtering at parent + spec.group default + new null-handling test). Ready for a look whenever you have a moment.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Comment thread frontend/src/components/resourceMap/sources/definitions/sources.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 121f373 to 89b7a2e Compare May 18, 2026 08:06
@WasThatRudy
Copy link
Copy Markdown
Contributor Author

WasThatRudy commented May 18, 2026

all five follow-ups are addressed in 89b7a2e:

  • lib/k8s/crd.tsconsole.warn now dedupes per CRD via a module-level Set keyed by metadata.uid (falling back to metadata.name). The first transient incomplete spec for a given CRD logs once; subsequent calls during the same session no longer spam.
  • components/crd/CustomResourceList.tsxtitle default and additionalPrinterCols lookup now use optional chaining on crd.spec?.names?.kind and crd.jsonData.spec?.versions?.find(...), so a transiently undefined spec doesn't crash before the !CRClass bail-out is reached.
  • components/resourceMap/sources/definitions/sources.tsxgenerateCRSources derives kind via crd.spec?.names?.kind and continues on missing, so an incomplete CRD can't crash the resource map before the makeCRClass() guard runs.
  • components/crd/CustomResourceInstancesList.tsx — removed the misleading key: string from CrInstancesView's props type; React's key attribute is still applied at the JSX site for remount semantics.
  • components/crd/CustomResourceDetails.test.tsx — added a regression test that mocks crd.makeCRClass() to return null and asserts the renderer shows the loader (via aria-label="Loading custom resource details") without mounting MainInfoSection.

cc @illume — pushed as an amend; lint, tsc, and the relevant suites (hooks.test.tsx, CustomResourceDetails.test.tsx, CustomResourceInstancesList.test.tsx) are green locally.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/components/crd/CustomResourceDetails.tsx Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx
@k8s-ci-robot k8s-ci-robot added size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. and removed needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. size/L Denotes a PR that changes 100-499 lines, ignoring generated files. labels May 20, 2026
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from f5bebd0 to 6f008f8 Compare May 20, 2026 16:47
@WasThatRudy WasThatRudy requested a review from Copilot May 20, 2026 18:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 26 out of 27 changed files in this pull request and generated 6 comments.

Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceDetails.tsx Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch 2 times, most recently from 646d118 to 81263ed Compare May 20, 2026 19:42
@WasThatRudy WasThatRudy requested a review from Copilot May 20, 2026 22:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/components/crd/CustomResourceDetails.tsx
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 81263ed to 9972482 Compare May 20, 2026 22:29
@WasThatRudy WasThatRudy requested a review from Copilot May 20, 2026 22:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/i18n/locales/zh/translation.json Outdated
Comment thread frontend/src/i18n/locales/zh/translation.json Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 9972482 to 45d533d Compare May 20, 2026 22:45
@WasThatRudy WasThatRudy requested a review from Copilot May 20, 2026 22:46
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 5 comments.

Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/lib/k8s/crdSpec.ts Outdated
@WasThatRudy WasThatRudy force-pushed the fix/crd-incomplete-spec-guards branch from 45d533d to 8ba2394 Compare May 20, 2026 22:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 4 comments.

Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceInstancesList.test.tsx Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 5 comments.

Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceDetails.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceDetails.test.tsx Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 4 comments.

Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/i18n/locales/de/translation.json Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
Comment thread frontend/src/lib/k8s/crd.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 2 comments.

Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/lib/k8s/crd.ts
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 2 comments.

Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceDetails.tsx Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 3 comments.

Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/components/crd/CustomResourceDetails.test.tsx
Comment thread frontend/src/lib/k8s/crd.ts Outdated
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 28 out of 29 changed files in this pull request and generated 4 comments.

Comment thread frontend/src/components/crd/CustomResourceList.tsx Outdated
Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/lib/k8s/crd.ts
Comment thread frontend/src/components/crd/CustomResourceInstancesList.tsx
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Copy Markdown
Contributor

@illume illume left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for these changes.

It looks like this PR has git conflicts. Can you please fix them?

How to resolve conflicts

Rebase or merge the latest main into your branch, resolve the conflicts, and push the updated branch.

`CustomResourceDefinition.makeCRClass`, `getMainAPIGroup`, the
`plural` getter, and `isNamespacedScope` all assumed `this.spec`,
`this.spec.versions`, and `this.spec.names` were fully populated.
When a CRD reaches one of these methods with a partial spec (a
transient watch update or in-flight refetch can leave the field
undefined for a moment) the nested access throws and the whole
dashboard view crashes with `Cannot read properties of undefined
(reading 'names')` or `(reading 'versions')`.

Adds defensive guards to all four:

  - `makeCRClass()` now returns `typeof KubeObject<KubeCRD> | null`.
    It logs a `console.warn` and returns null when spec is missing
    or has no versions/names, instead of crashing on the map.
  - `getMainAPIGroup()` returns `['', '', '']` when spec is
    undefined.
  - `get plural()` returns `''` when spec.names is missing.
  - `get isNamespacedScope()` returns false when spec is missing.

All five production call sites of `makeCRClass()` now handle the
nullable return:

  - `CustomResourceDetails.tsx` skips `useGet` and renders the
    existing Loader while the spec is incomplete.
  - `CustomResourceInstancesList.tsx` flat-maps to drop CRDs that
    haven't fully loaded, so the list view continues to render the
    healthy CRDs.
  - `CustomResourceList.tsx` widens the local type annotation; the
    `if (!CRClass)` branch already in the file renders an empty
    state.
  - `resourceMap/sources/definitions/sources.tsx` skips the CRD
    rather than creating a broken graph source.
  - `resourceMap/sources/definitions/relations.tsx` flat-maps to
    drop incomplete CRDs.

A unit test for `makeCRClass()` would have been ideal but is blocked
by a pre-existing circular-import issue in `lib/k8s/`: `crd.ts`
imports `ResourceClasses` from `./index`, which transitively loads
`deployment.ts` and `replicaSet.ts` in a cycle that vitest cannot
resolve. The existing component tests in `crd/` mock the crd module
entirely; they continue to pass on this branch (7/7).

This is a defensive fix at the consumer boundary. The deeper question
of why a CRD reaches these methods with a partial spec (websocket
ADDED with incomplete payload, query cache trimming, etc.) is left
for a follow-up that needs reproduction or maintainer guidance.

Bug report: kubernetes-sigs#4824.

Signed-off-by: Rudraksha Singh Sengar <rudraksharss@gmail.com>
@WasThatRudy
Copy link
Copy Markdown
Contributor Author

@illume done. i have rebased the PR, it does not have conflicts anymore.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cncf-cla: yes Indicates the PR's author has signed the CNCF CLA. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Crash Report: Cannot read properties of undefined (reading 'names')

4 participants