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
- Prefix the variable with RC_APPS_<APPID>_ (e.g. RC_APPS_<APPID>_API_KEY).
- Use only NODE_ENV, ROOT_URL, or INSTANCE_IP for non-prefixed reads.
- 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
- Namespace all app-specific env vars under RC_APPS_<APPID>_.
- Whitelist expected names in your app config and validate against them.
- Use isReadable (throw-free) as the probe before getValueByName.
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
- Invalid Api parameter provided, it must be a valid IApi obje
- Invalid command parameter provided, must be a string.
- Invalid Slash Command parameter provided, it must be a valid
- auth option should be of the form "username:password"
- Invalid token for livechat message
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/cbf30648fc30e049.
Report an issue: GitHub.