{"record":{"id":"c231e6d04bd18514","repo":"SonarSource/sonarqube","slug":"setting-s-can-only-be-used-in-sonar-properties","errorCode":null,"errorMessage":"Setting '%s' can only be used in sonar.properties","messagePattern":"Setting '(.+?)' can only be used in sonar\\.properties","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":400,"severity":"error","filePath":"server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java","lineNumber":53,"sourceCode":"\n@ServerSide\npublic class SettingsWsSupport {\n  public static final String DOT_SECURED = \".secured\";\n  @VisibleForTesting\n  static final Set<String> ADMIN_ONLY_SETTINGS = Set.of(\"sonar.auth.bitbucket.workspaces\", \"sonar.auth.github.organizations\");\n\n  private final UserSession userSession;\n\n  public SettingsWsSupport(UserSession userSession) {\n    this.userSession = userSession;\n  }\n\n  static void validateKey(String key) {\n    stream(ProcessProperties.Property.values())\n      .filter(property -> property.getKey().equalsIgnoreCase(key))\n      .findFirst()\n      .ifPresent(property -> {\n        throw new IllegalArgumentException(format(\"Setting '%s' can only be used in sonar.properties\", key));\n      });\n  }\n\n  boolean isVisible(String key, Optional<EntityDto> component) {\n    if (isAdmin(component)) {\n      return true;\n    }\n    return hasPermission(GlobalPermission.SCAN, ProjectPermission.SCAN, component) || !isProtected(key);\n  }\n\n  private boolean isAdmin(Optional<EntityDto> component) {\n    return userSession.isSystemAdministrator() || hasPermission(GlobalPermission.ADMINISTER, ADMIN, component);\n  }\n\n  private static boolean isProtected(String key) {\n    return isSecured(key) || isAdminOnly(key);\n  }\n","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-webserver-webapi/src/main/java/org/sonar/server/setting/ws/SettingsWsSupport.java#L35-L71","documentation":"Some properties (ProcessProperties.Property enum values) are boot-time settings that can only be defined in sonar.properties on the server; SettingsWsSupport.validateKey rejects any attempt to store them via the web service settings API. Throwing happens before any read/write, returning 400 to the caller.","triggerScenarios":"Calling api/settings/set (or api/settings/values) with key equal (case-insensitively) to any ProcessProperties.Property key, e.g. sonar.web.port, sonar.path.data, sonar.cluster.*.","commonSituations":"Automation trying to move ALL sonar.* configuration into DB-stored settings; operators confusing runtime settings with bootstrap properties; copy-pasting sonar.properties content into the UI.","solutions":["Set the property in conf/sonar.properties on the SonarQube server and restart","Remove the key from API automation and keep only DB-managed settings there","Rename the key if it was a typo colliding with a reserved ProcessProperties key"],"exampleFix":"// before\nPOST /api/settings/set?key=sonar.web.port&value=9001\n// after\n# conf/sonar.properties\nsonar.web.port=9001   (then restart server)","handlingStrategy":"validation","validationCode":"const PROCESS_PROPERTY_KEYS = new Set(['sonar.web.port','sonar.path.data' /* ...ProcessProperties keys */]);\nif (PROCESS_PROPERTY_KEYS.has(key.toLowerCase())) throw new Error(`'${key}' belongs in sonar.properties`);","typeGuard":"function isProcessProperty(key) { return processPropertyKeys.some(k => k.toLowerCase() === key.toLowerCase()); }","tryCatchPattern":"try { await setSetting(key, v); } catch (e) { if (/can only be used in sonar\\.properties/.test(e.message)) { applyToServerProperties(key, v); return; } throw e; }","preventionTips":["Classify settings as DB-managed vs boot-time before writing automation","Maintain a deny-list of ProcessProperties keys in tooling","When a key does not appear in api/settings/definitions, suspect it is a sonar.properties-only property"],"tags":["settings","configuration","api","server-config"],"backgroundTag":"invalid-config-value","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}