{"record":{"id":"fd3e20086d5a61af","repo":"RocketChat/Rocket.Chat","slug":"the-setting-setting-id-is-not-readable","errorCode":null,"errorMessage":"The setting \"${setting.id}\" is not readable.","messagePattern":"The setting \"(.+?)\" is not readable\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/meteor/app/apps/server/bridges/settings.ts","lineNumber":101,"sourceCode":"\n\t\tconst readSettings = readSettingsPermission as IReadSettingPermission;\n\t\t// If the setting is in the hiddenSettings list (defined within the permission), then it can bypass the hidden flag.\n\t\t// 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.\n\t\tconst setting = readSettings.hiddenSettings?.includes(id) ? await Settings.findOneById(id) : await Settings.findOneNotHiddenById(id);\n\n\t\tif (!setting) {\n\t\t\tthis.orch.debugLog(`The setting ${id} is not found.`);\n\t\t\treturn null;\n\t\t}\n\n\t\treturn this.orch.getConverters()?.get('settings').convertToApp(setting);\n\t}\n\n\tprotected async updateOne(setting: ISetting & { id: string }, appId: string): Promise<void> {\n\t\tthis.orch.debugLog(`The App ${appId} is updating the setting ${setting.id} .`);\n\n\t\tif (!(await this.isReadableById(setting.id, appId))) {\n\t\t\tthrow new Error(`The setting \"${setting.id}\" is not readable.`);\n\t\t}\n\n\t\tif (\n\t\t\t(\n\t\t\t\tawait updateAuditedByApp({\n\t\t\t\t\t_id: appId,\n\t\t\t\t})(Settings.updateValueById, setting.id, setting.value)\n\t\t\t).modifiedCount\n\t\t) {\n\t\t\tvoid notifyOnSettingChangedById(setting.id);\n\t\t}\n\t}\n\n\tprotected async incrementValue(id: string, value: number, appId: string): Promise<void> {\n\t\tthis.orch.debugLog(`The App ${appId} is incrementing the value of the setting ${id}.`);\n\n\t\tif (!(await this.isReadableById(id, appId))) {\n\t\t\tthrow new Error(`The setting \"${id}\" is not readable.`);","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/app/apps/server/bridges/settings.ts#L83-L119","documentation":"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.","triggerScenarios":"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.","commonSituations":"Apps writing configuration such as SMTP/OAuth credentials (secret settings); settings renamed across major server upgrades; case-sensitive id mismatches.","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."],"exampleFix":"// before\nawait updateSetting({ id: 'SMTP_Password', value }, appId); // secret -> throws\n\n// after\nawait updateSetting({ id: 'SMTP_Host', value }, appId); // exists and is not secret","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"Catch, log the setting id, and skip the update; surface an admin action item when the target is a secret setting.","preventionTips":["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."],"tags":["apps-engine","settings","permissions","secret-setting"],"backgroundTag":"setting-not-readable","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}