From c5494732c2292a51f6c0e41b8023c6d90eff0ab1 Mon Sep 17 00:00:00 2001 From: kan ritsuha Date: Wed, 9 Sep 2026 18:26:24 +0900 Subject: [PATCH] NO-JIRA: do not fall back to the raw resource field for empty children DetailsItem resolved its rendered value with `children || _.get(obj, path, defaultValue)`. An empty child therefore fell through to the raw resource field, which for paths such as `metadata.annotations` is a plain object. React rejects a plain object as a child, so the whole details page crashes with "Objects are not valid as a React child" (minified error #31). This is reachable today on the Route details page in the Japanese locale. The Annotations item renders `t('{{count}} annotation', { count })` as its child when the user cannot patch the Route, and `useAccessReview` starts out as `false` while the SelfSubjectAccessReview is still in flight, so the very first render always takes that branch. In the `ja` locale `{{count}} annotation_other` resolves to an empty string, the fallback kicks in and `metadata.annotations` is handed to React, which throws before the access review resolves. Routes carrying two or more annotations are affected. Routes managed by Argo CD always are, because they carry both `argocd.argoproj.io/tracking-id` and `kubectl.kubernetes.io/last-applied-configuration`. Routes with a single annotation render fine, because `{{count}} annotation_one` is absent from the `ja` resource and the i18next fallback returns a non-empty string. The broken `ja` translations were repaired separately in 00e08ca, which removes the trigger but not the fallback that turns a falsy child into a rendered object. Use `??` so the raw resource field is used only when no children were provided at all. --- src/utils/components/DetailsItem/DetailsItem.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/utils/components/DetailsItem/DetailsItem.tsx b/src/utils/components/DetailsItem/DetailsItem.tsx index ef2337b3..8ff66a01 100644 --- a/src/utils/components/DetailsItem/DetailsItem.tsx +++ b/src/utils/components/DetailsItem/DetailsItem.tsx @@ -82,7 +82,11 @@ export const DetailsItem: FC = ({ const hide = hideEmpty && _.isEmpty(_.get(obj, path)); const popoverContent: string = description ?? getPropertyDescription(model, path); - const value: ReactNode = children || _.get(obj, path, defaultValue); + // Fall back to the raw resource field only when no children were provided at all. + // An empty or falsy child (for example a missing translation resolving to an empty + // string) must not fall through, otherwise a plain object such as + // metadata.annotations is handed to React as a child and the page crashes. + const value: ReactNode = children ?? _.get(obj, path, defaultValue); const editable = onEdit && canEdit; return hide ? null : (