Air-gapped warning crashes admin UI: Trans <1> targets remainingDays instead of Box (8.9.0 / develop)

Open
#43,438 1 comment 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@Kulraj69 is already working on this.

Since Nov 2, 2026.

  • #43451 by @Kulraj69 — open

Assessment

Difficulty
3/5
Estimated time
1-2 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Active
Tech stack
react, react-native, typescript

Research direction

The bug lives in apps/meteor/client/sidebar/sections/AirGappedRestrictionBanner/AirGappedRestrictionWarning.tsx, where the Trans children order makes the <1> tag in packages/i18n/src/locales/en.i18n.json point at remainingDays rather than the Box. Read the two Trans branches and the Airgapped_workspace_warning and restriction keys first, then reproduce with the isolated script in the issue. Done means both sentences render for days 7 through 1 and at zero, with a regression test covering both branches; a pull request (#43451) is already open, so check it before starting.

Written by the indexing model from the issue text.

Description

type: bug
Description

The air-gapped workspace warning can crash the administrator's web UI with React error #130 (Element type is invalid ... got: undefined). The Airgapped_workspace_warning translation uses <1>...</1>, but child index 1 of its <Trans> component is the numeric remainingDays value, not the intended <Box> element.

This is reproducible for every remaining-day value from 7 through 1 in both:

  • Rocket.Chat 8.9.0, commit 057a927d903c83b5d61cf236d650c4500ebb4b66.
  • develop, commit 9971f492da4960edce747fa9feb07c7fc332dbac (checked November 2, 2026).

There is a related rendering defect at remainingDays = 0: the restricted-mode branch does not crash in the isolated reproduction, but the second sentence disappears because its translation also references the wrong child index.

Relevant source

Permalinks to the checked develop commit:

Steps to reproduce
  1. In a test environment, render the sidebar as an administrator with the air-gap warning phase active (Cloud_Workspace_AirGapped_Restrictions_Remaining_Days between 1 and 7).
  2. Use the English locale.
  3. Render the sidebar warning, for example with remainingDays = 6.
  4. Observe the React render exception. Repeat with 7, 5, 4, 3, 2, and 1: the same error occurs.

The component-level reproduction below does not require a running server or any license/configuration changes:

npm install [email protected] [email protected] [email protected] [email protected]
node repro.mjs
// repro.mjs
import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';
import { createInstance } from 'i18next';
import { Trans, I18nextProvider } from 'react-i18next';

const i18n = createInstance();
await i18n.init({
  lng: 'en',
  defaultNS: 'core',
  resources: {
    en: { core: {
      Airgapped_workspace_warning:
        'This air-gapped workspace will enter read-only mode in {{remainingDays}} days. <1>Connect it to the internet or upgrade to a premium plan to prevent this.</1>',
    } },
  },
  interpolation: { escapeValue: false },
});

for (const remainingDays of [7, 6, 5, 4, 3, 2, 1]) {
  // The same child ordering as the JSX in AirGappedRestrictionWarning.
  // A span replaces the presentation-only Box wrapper.
  const warning = React.createElement(Trans, {
    i18nKey: 'Airgapped_workspace_warning',
    values: { remainingDays },
    children: [
      'This air-gapped workspace will enter read-only mode in ',
      remainingDays,
      ' days.',
      ' ',
      React.createElement('span', { key: 'detail' },
        'Connect it to internet or upgrade to a premium plan to prevent this.'),
    ],
  });
  try {
    console.log(remainingDays, renderToStaticMarkup(
      React.createElement(I18nextProvider, { i18n }, warning)));
  } catch (error) {
    console.log(remainingDays, error.message);
  }
}

Repeat with [email protected] for the checked develop dependency version: the same failure occurs.

Expected behavior

The administrator can continue using the UI while the complete warning is displayed, including the remaining days and the explanatory second sentence. At zero days, the complete read-only notification should render.

Actual behavior / root cause

The warning's children are:

Index Value
0 Initial text
1 remainingDays (a number)
2 " days."
3 " "
4 The intended Box / span

The translation's <1> targets the number. Trans produces a React element with an undefined type, and React throws. The issue is the child's position/type, not any particular numeric value.

For the restricted-mode branch, the intended Box is at index 2, while <1> refers to the explicit whitespace child. The second sentence is consequently omitted in the reproduction.

Validation

An isolated server-side render test transpiled the actual TSX component from each checked Git ref and loaded that ref's English translations. Only the presentation-only Fuselage Box wrapper was replaced with a span; the Trans JSX was unchanged. A full Rocket.Chat server deployment was not started for this version comparison.

Version React / React DOM react-i18next i18next Days 7–1 Days 0
8.9.0 19.2.8 17.0.14 26.4.2 Render exception for every value Second sentence missing
develop 9971f492 19.2.8 17.0.16 26.4.2 Render exception for every value Second sentence missing

As a diagnostic control, changing the warning's translation tag from <1> to <4> makes every tested positive-day case render successfully. Changing the restricted branch's tag from <1> to <2> restores its second sentence. These controls were applied only in the isolated test resources.

Proposed solution

Prefer an explicit named component instead of relying on JSX child positions, and keep interpolation exclusively in values:

<Trans
  i18nKey={isRestricted ? 'Airgapped_workspace_restriction' : 'Airgapped_workspace_warning'}
  values={{ remainingDays }}
  components={{ detail: <Box fontScale='p2' is='span' /> }}
/>

Update both translation keys to use <detail>...</detail> consistently across locales. For example:

{
  "Airgapped_workspace_warning": "This air-gapped workspace will enter read-only mode in {{remainingDays}} days. <detail>Connect it to the internet or upgrade to a premium plan to prevent this.</detail>",
  "Airgapped_workspace_restriction": "This air-gapped workspace is in read-only mode. <detail>Connect it to the internet or upgrade to a premium plan to restore full functionality.</detail>"
}

Alternatively, an explicit indexed components mapping could preserve existing <1> translations without relying on implicit children. Merely changing English indices would leave other locales vulnerable and retain fragile coupling to JSX layout.

Suggested regression coverage: render both branches with real locale resources; parameterize days 1–7; assert both sentences and the interpolated day count; verify the zero-day restricted branch; cover a non-English locale and English fallback. This fix should affect presentation only, leaving air-gap detection and restriction behavior unchanged.

Relevant logs
Minified React error #130 ... args[]=undefined

Element type is invalid: expected a string (for built-in components)
or a class/function (for composite components) but got: undefined.

Server topology, database version, and installation-specific information are not needed for the isolated reproduction above.

Dominant language
TypeScript
Stars
46.5k
Forks
14.1k
Avg merge
1d 21h
Merged PRs (30d)
381

Getting set up

Open in Codespaces

Starts the project's dev container in your browser, under your own GitHub account.

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from RocketChat/Rocket.Chat

All issues in RocketChat/Rocket.Chat

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.