{"record":{"id":"ac33c028026e09ab","repo":"apache/druid","slug":"dot-at-the-end-of-property-s","errorCode":null,"errorMessage":"Dot at the end of property: %s","messagePattern":"Dot at the end of property: (.+?)","errorType":"validation","errorClass":"ProvisionException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/guice/JsonConfigurator.java","lineNumber":240,"sourceCode":"      String originalProperty,\n      String property,\n      Object value,\n      Map<String, Object> targetMap\n  )\n  {\n    int dotIndex = property.indexOf('.');\n    // Always put property with name even if it is of form a.b. This will make sure the property is available for classes\n    // where JsonProperty names are of the form a.b\n    // Note:- this will cause more than required properties to be present in the jsonMap.\n    targetMap.put(property, value);\n    if (dotIndex < 0) {\n      return;\n    }\n    if (dotIndex == 0) {\n      throw new ProvisionException(StringUtils.format(\"Double dot in property: %s\", originalProperty));\n    }\n    if (dotIndex == property.length() - 1) {\n      throw new ProvisionException(StringUtils.format(\"Dot at the end of property: %s\", originalProperty));\n    }\n    String nestedKey = property.substring(0, dotIndex);\n    Object nested = targetMap.computeIfAbsent(nestedKey, k -> new HashMap<String, Object>());\n    if (!(nested instanceof Map)) {\n      // Clash is possible between properties, which are used to configure different objects: e. g.\n      // druid.emitter=parametrized is used to configure Emitter class, and druid.emitter.parametrized.xxx=yyy is used\n      // to configure ParametrizedUriEmitterConfig object. So skipping xxx=yyy key-value pair when configuring Emitter\n      // doesn't make any difference. That is why we just log this situation, instead of throwing an exception.\n      log.info(\n          \"Skipping property [%s]: one of it's prefixes [%s] is also used as a property key.\",\n          originalProperty,\n          propertyPrefix\n      );\n      return;\n    }\n    Map<String, Object> nestedMap = (Map<String, Object>) nested;\n    hieraricalPutValue(propertyPrefix, originalProperty, property.substring(dotIndex + 1), value, nestedMap);\n  }","sourceCodeStart":222,"sourceCodeEnd":258,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/guice/JsonConfigurator.java#L222-L258","documentation":"hieraricalPutValue builds nested maps from dotted property keys; a key ending with a dot would produce an empty final segment, which cannot map to a config field. Druid throws ProvisionException 'Dot at the end of property' to fail fast on the malformed key.","triggerScenarios":"hieraricalPutValue sees dotIndex == property.length() - 1, i.e. the property key string ends in '.' — triggered from configurate or recursively from hieraricalPutValue itself.","commonSituations":"A runtime.properties line like 'druid.emitter.=parametrized' or 'druid.storage.type.=' left after deleting the leaf key but not the trailing dot, often from manual editing or find/replace.","solutions":["Remove the trailing dot from the listed property key so it ends with an actual key segment","Delete the whole line if the property is no longer needed","Regenerate or lint runtime.properties with a validator that rejects keys ending in '.'"],"exampleFix":"// before\ndruid.emitter.=parametrized\n// after\ndruid.emitter=parametrized","handlingStrategy":"validation","validationCode":"for (String key : props.stringPropertyNames()) {\n  if (key.endsWith(\".\")) throw new IllegalArgumentException(\"Trailing dot in property key: \" + key);\n}","typeGuard":null,"tryCatchPattern":"try { injector = Guice.createInjector(...); } catch (ProvisionException e) { if (e.getMessage().contains(\"Dot at the end\")) log.error(\"Fix trailing-dot property key\"); throw e; }","preventionTips":["When deleting a leaf config value, delete the whole line rather than leaving 'key.='","Run a properties lint step before distributing configs to nodes","Use diff review on runtime.properties changes"],"tags":["guice","configuration","property-parsing","startup"],"backgroundTag":"invalid-config-value","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}