{"record":{"id":"3d21bd94d1e06691","repo":"grpc/grpc-java","slug":"configurators-are-already-set","errorCode":null,"errorMessage":"Configurators are already set","messagePattern":"Configurators are already set","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"api/src/main/java/io/grpc/ConfiguratorRegistry.java","lineNumber":60,"sourceCode":"  /**\n   * Returns the default global instance of the configurator registry.\n   */\n  public static synchronized ConfiguratorRegistry getDefaultRegistry() {\n    if (instance == null) {\n      instance = new ConfiguratorRegistry();\n    }\n    return instance;\n  }\n\n  /**\n   * Sets the configurators in this registry. This method can only be called once.\n   *\n   * @param configurators the configurators to set\n   * @throws IllegalStateException if this method is called more than once\n   */\n  public synchronized void setConfigurators(List<? extends Configurator> configurators) {\n    if (wasConfiguratorsSet) {\n      throw new IllegalStateException(\"Configurators are already set\");\n    }\n    this.configurators = Collections.unmodifiableList(new ArrayList<>(configurators));\n    wasConfiguratorsSet = true;\n  }\n\n  /**\n   * Returns a list of the configurators in this registry.\n   */\n  public synchronized List<Configurator> getConfigurators() {\n    if (!wasConfiguratorsSet) {\n      configuratorsCallCountBeforeSet++;\n    }\n    return configurators;\n  }\n\n  /**\n   * Returns the number of times getConfigurators() was called before\n   * setConfigurators() was successfully invoked.","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/api/src/main/java/io/grpc/ConfiguratorRegistry.java#L42-L78","documentation":"ConfiguratorRegistry.setConfigurators() is a write-once API: it stores an unmodifiable snapshot of the configurators and flips a wasConfiguratorsSet flag. Any second call — even with an identical or empty list — throws IllegalStateException because reconfiguration after initialization would violate the registry's invariants.","triggerScenarios":"Calling setConfigurators() twice on the same registry instance, e.g. re-running initialization code, re-invoking a setup method during retry or hot-reload, or two independent components both attempting to install their configurator lists into a shared registry.","commonSituations":"Application bootstrap code executed more than once (redeployment hooks, Spring bean post-processing duplicates, tests reusing a registry across cases); plugin systems where multiple modules each try to register configurators; accidental reconfiguration on config refresh.","solutions":["Call setConfigurators() exactly once per registry instance, before any read/use","Wrap the call in an idempotency check or set a local boolean so retries don't re-invoke it","If configurators must change, create a new registry instance instead of reconfiguring the existing one"],"exampleFix":"// before\nregistry.setConfigurators(configurators); // may run again on reload\n// after\nif (!initialized) {\n  registry.setConfigurators(configurators);\n  initialized = true;\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"boolean canSetConfigurators(ConfiguratorRegistry registry) {\n  try {\n    java.lang.reflect.Field f = ConfiguratorRegistry.class.getDeclaredField(\"wasConfiguratorsSet\");\n    f.setAccessible(true);\n    return !f.getBoolean(registry);\n  } catch (ReflectiveOperationException e) {\n    return false;\n  }\n}","tryCatchPattern":"try {\n  registry.setConfigurators(configurators);\n} catch (IllegalStateException e) {\n  if (\"Configurators are already set\".equals(e.getMessage())) {\n    // idempotent re-init: keep existing configurators\n  } else throw e;\n}","preventionTips":["Design bootstrap so setConfigurators is called exactly once, guarded by a boolean or singleton initialization","Make reconfiguration create a new registry rather than mutating an initialized one","Guard against duplicate initialization in tests by using fresh registry instances per test"],"tags":["illegal-state","initialization","write-once","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}