RocketChat/Rocket.Chat · error · Error

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

Error message

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

What it means

Thrown by updateOne when the app attempts to modify a setting it is not allowed to read. The same isReadableById gate used by getOneById guards writes: if the setting is hidden/secret, missing, or outside the app's server-setting.read permission, the update is rejected before Settings.updateValueById runs.

Source

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

		const readSettings = readSettingsPermission as IReadSettingPermission;
		// If the setting is in the hiddenSettings list (defined within the permission), then it can bypass the hidden flag.
		// If not, then it must be a non-hidden setting. This is to allow apps to read hidden settings if they have the permission to do so.
		const setting = readSettings.hiddenSettings?.includes(id) ? await Settings.findOneById(id) : await Settings.findOneNotHiddenById(id);

		if (!setting) {
			this.orch.debugLog(`The setting ${id} is not found.`);
			return null;
		}

		return this.orch.getConverters()?.get('settings').convertToApp(setting);
	}

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

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

		if (
			(
				await updateAuditedByApp({
					_id: appId,
				})(Settings.updateValueById, setting.id, setting.value)
			).modifiedCount
		) {
			void notifyOnSettingChangedById(setting.id);
		}
	}

	protected async incrementValue(id: string, value: number, appId: string): Promise<void> {
		this.orch.debugLog(`The App ${appId} is incrementing the value of 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 server-setting.read (and the write permission your app needs) for the setting id in the app manifest.
  2. Read the setting first to confirm it exists and is readable before updating.
  3. Catch the error and inform the admin rather than leaving the app in a broken state.

Example fix

// before
await modify.getSettings().updateOne({ id: 'My_Setting', value: 'x' });

// after
// app.json permissions include server-setting.read with 'My_Setting'
const readable = await read.getEnvironmentReader().getServerSettings().isReadableById('My_Setting');
if (!readable) {
  // handle gracefully
  return;
}
await modify.getSettings().updateOne({ id: 'My_Setting', value: 'x' });
Defensive patterns

Strategy: validation

Validate before calling

const readable = await read.getEnvironmentReader().getServerSettings().isReadableById(setting.id);
if (!readable) {
  throw new Error(`Cannot update unreadable setting ${setting.id}`);
}

Try / catch

try {
  await modify.getSettings().updateOne({ id, value });
} catch (err) {
  if (err instanceof Error && err.message.includes('is not readable')) {
    // declare permission or pick a writable setting
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: App calls updateOne with a setting id it has no read permission for, or for a setting that does not exist.

Common situations: App tries to write an admin-only or hidden setting without declaring the permission; setting was removed/renamed in a server version bump; app persists a cached setting id that is no longer valid.

Related errors


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