RocketChat/Rocket.Chat · error
The setting " " is not readable.
Error message
The setting "${setting.id}" is not readable. What it means
updateOne on the settings bridge first asserts isReadableById, which requires the setting to exist and not be flagged secret. Updating an unknown id or a secret setting (passwords, keys) fails with 'The setting ... is not readable.' before any write happens.
Solutions
- Confirm the setting id exists on this server version.
- Secret settings cannot be updated by apps; have an administrator change them in the UI, or use a non-secret setting.
- Re-check ids after server upgrades — settings are renamed or removed across versions.
Example fix
// before
await updateSetting({ id: 'SMTP_Password', value }, appId); // secret -> throws
// after
await updateSetting({ id: 'SMTP_Host', value }, appId); // exists and is not secret Defensive patterns
Strategy: try-catch
Try / catch
Catch, log the setting id, and skip the update; surface an admin action item when the target is a secret setting.
Prevention
- Keep a list of setting ids your app touches and verify them per server version.
- Never target secret settings for app-driven updates.
- Prefer non-secret settings or app persistence for app-managed values.
When it happens
Trigger: App updates a server setting whose id does not exist on this server (typo, removed/renamed in another Rocket.Chat version), or updates a setting defined with secret: true.
Common situations: Apps writing configuration such as SMTP/OAuth credentials (secret settings); settings renamed across major server upgrades; case-sensitive id mismatches.
Related errors
- The setting " " is not readable.
- error-action-not-allowed
- error-action-not-allowed
- error-action-not-allowed
- error-action-not-allowed
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/fd3e20086d5a61af.
Report an issue: GitHub.
Appendix: 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 b2c16d5842)