RocketChat/Rocket.Chat · error · Error

The environmental variable "${envVarName}" is not readable.

Error message

The environmental variable "${envVarName}" is not readable.

What it means

`AppEnvironmentalVariableBridge.getValueByName` (environmental.ts:12-20) returns an env var's value, but only after `isReadable` passes. A variable is readable if its uppercased name is in the hardcoded allowlist (`NODE_ENV`, `ROOT_URL`, `INSTANCE_IP`) OR it starts with `RC_APPS_<APPID>_` (appId uppercased, dashes to underscores) — see isAppsOwnVariable (environmental.ts:28-34). Otherwise the bridge throws; apps cannot read arbitrary process.env entries.

Source

Thrown at apps/meteor/app/apps/server/bridges/environmental.ts:16

import type { IAppServerOrchestrator } from '@rocket.chat/apps';
import { EnvironmentalVariableBridge } from '@rocket.chat/apps/dist/server/bridges/EnvironmentalVariableBridge';

export class AppEnvironmentalVariableBridge extends EnvironmentalVariableBridge {
	allowed: Array<string>;

	constructor(private readonly orch: IAppServerOrchestrator) {
		super();
		this.allowed = ['NODE_ENV', 'ROOT_URL', 'INSTANCE_IP'];
	}

	protected async getValueByName(envVarName: string, appId: string): Promise<string | undefined> {
		this.orch.debugLog(`The App ${appId} is getting the environmental variable value ${envVarName}.`);

		if (!(await this.isReadable(envVarName, appId))) {
			throw new Error(`The environmental variable "${envVarName}" is not readable.`);
		}

		return process.env[envVarName];
	}

	protected async isReadable(envVarName: string, appId: string): Promise<boolean> {
		this.orch.debugLog(`The App ${appId} is checking if the environmental variable is readable ${envVarName}.`);

		return this.allowed.includes(envVarName.toUpperCase()) || this.isAppsOwnVariable(envVarName, appId);
	}

	protected isAppsOwnVariable(envVarName: string, appId: string): boolean {
		/**
		 * Replace the letter `-` with `_` since environment variable name doesn't support it
		 */
		const appVariablePrefix = `RC_APPS_${appId.toUpperCase().replace(/-/g, '_')}`;
		return envVarName.toUpperCase().startsWith(appVariablePrefix);
	}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Prefix the variable with RC_APPS_<APPID>_ (e.g. RC_APPS_<APPID>_API_KEY).
  2. Use only NODE_ENV, ROOT_URL, or INSTANCE_IP for non-prefixed reads.
  3. Call isReadable first (it returns a boolean and does not throw) to check without failing.

Example fix

// before
const v = await envReader.getValueByName('API_KEY')
// after (set env RC_APPS_<APPID>_API_KEY, then)
const v = await envReader.getValueByName(`RC_APPS_${appId.toUpperCase().replace(/-/g, '_')}_API_KEY`)
Defensive patterns

Strategy: validation

Validate before calling

async function safeGetEnv(envReader: any, name: string): Promise<string | undefined> {
  if (!(await envReader.isReadable(name))) {
    return undefined; // not allowed; do not call getValueByName
  }
  return envReader.getValueByName(name);
}

Prevention

When it happens

Trigger: App calls `environmentVariableReader.getValueByName('SECRET_TOKEN')` where the name is neither allowlisted nor prefixed with RC_APPS_<APPID>_.

Common situations: App trying to read a secret/config var without the required prefix; developer unaware of the allowlist; appId-derived prefix computed incorrectly (e.g. dashes not replaced).

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12). Data as JSON: /api/errors/cbf30648fc30e049. Report an issue: GitHub.