RocketChat/Rocket.Chat · error · Error

The setting "${id}" is not readable.

Error message

The setting "${id}" is not readable.

What it means

Thrown by getOneById when getReadableSettingById returns null. A setting is 'not readable' if it does not exist, is hidden and the app lacks explicit permission, the app has no server-setting.read permission, or the app itself is not found in the manager. Readability is gated by the app's declared permissions, not just the secret/hidden flag.

Source

Thrown at apps/meteor/app/apps/server/bridges/settings.ts:27

export class AppSettingBridge extends ServerSettingBridge {
	constructor(private readonly orch: IAppServerOrchestrator) {
		super();
	}

	protected async getAll(appId: string): Promise<Array<ISetting>> {
		this.orch.debugLog(`The App ${appId} is getting all the settings.`);

		const settings = await Settings.find({ secret: false }).toArray();
		return settings.map((s) => this.orch.getConverters()?.get('settings').convertToApp(s));
	}

	protected async getOneById(id: string, appId: string): Promise<ISetting> {
		this.orch.debugLog(`The App ${appId} is getting the setting by id ${id}.`);

		const setting = await this.getReadableSettingById(id, appId);
		if (!setting) {
			throw new Error(`The setting "${id}" is not readable.`);
		}

		return setting;
	}

	protected async hideGroup(name: string, appId: string): Promise<void> {
		this.orch.debugLog(`The App ${appId} is hidding the group ${name}.`);

		throw new Error('Method not implemented.');
	}

	protected async hideSetting(id: string, appId: string): Promise<void> {
		this.orch.debugLog(`The App ${appId} is hidding the setting ${id}.`);

		if (!(await this.isReadableById(id, appId))) {
			throw new Error(`The setting "${id}" is not readable.`);
		}

View on GitHub (pinned to f9d3ec372b)

Solutions

  1. Declare a server-setting.read permission in the app's manifest with the needed hiddenSettings entries.
  2. Confirm the setting id exists and is not hidden, or request access explicitly.
  3. Use getAll() to discover the actually-readable setting ids instead of guessing.

Example fix

// before
const siteUrl = await read.getEnvironmentReader().getServerSettings().getOneById('Site_Url');

// after
// app.json: declare permission
// {
//   "permissions": [{ "name": "server-setting.read", "hiddenSettings": ["Site_Url"] }]
// }
const siteUrl = await read.getEnvironmentReader().getServerSettings().getOneById('Site_Url');
Defensive patterns

Strategy: validation

Validate before calling

const readable = await read.getEnvironmentReader().getServerSettings().isReadableById(id);
if (!readable) {
  throw new Error(`App cannot read setting ${id}; check permissions`);
}

Try / catch

try {
  const s = await read.getEnvironmentReader().getServerSettings().getOneById(id);
} catch (err) {
  if (err instanceof Error && err.message.includes('is not readable')) {
    // declare server-setting.read permission or use a different setting
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: App calls getOneById(id) for a setting id that is hidden/secret, does not exist, or is outside the app's declared server-setting.read scope (including when the app declares no permissions at all).

Common situations: App tries to read an internal/admin-only setting it never declared permission for; setting id is misspelled; the setting was removed in a newer Rocket.Chat version; app's permission declaration is missing the hiddenSettings entry for a hidden setting it legitimately needs.

Related errors


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