{"record":{"id":"1745471e3fc6375b","repo":"apple/pkl","slug":"leaf-node-s-of-type-s-does-not-have-a-child","errorCode":null,"errorMessage":"Leaf node `%s` of type `%s` does not have a child named `%s`.","messagePattern":"Leaf node `(.+?)` of type `(.+?)` does not have a child named `(.+?)`\\.","errorType":"exception","errorClass":"NoSuchChildException","httpStatus":null,"severity":"error","filePath":"pkl-config-java/src/main/java/org/pkl/config/java/LeafConfig.java","lineNumber":36,"sourceCode":"import org.pkl.config.java.mapper.ValueMapper;\nimport org.pkl.core.PClassInfo;\n\nclass LeafConfig extends AbstractConfig {\n  private final Object value;\n\n  LeafConfig(String qualifiedName, ValueMapper mapper, Object value) {\n    super(qualifiedName, mapper);\n    this.value = value;\n  }\n\n  @Override\n  public Object getRawValue() {\n    return value;\n  }\n\n  @Override\n  protected Object getRawChildValue(String propertyName) {\n    throw new NoSuchChildException(\n        String.format(\n            \"Leaf node `%s` of type `%s` does not have a child named `%s`.\",\n            qualifiedName, PClassInfo.forValue(value).getQualifiedName(), propertyName),\n        propertyName);\n  }\n}\n","sourceCodeStart":18,"sourceCodeEnd":43,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-config-java/src/main/java/org/pkl/config/java/LeafConfig.java#L18-L43","documentation":"LeafConfig wraps a scalar Pkl value (string, int, boolean, etc.). By definition a leaf has no children, so any attempt to read a child property from it unconditionally throws NoSuchChildException naming the leaf's value type and the requested child name. The error exists to convert a structural mistake — treating a scalar as an object — into a clear diagnostic.","triggerScenarios":"Calling getChild/property accessors (routed to getRawChildValue) on a config node that wraps a leaf value, e.g. config.get(\"someScalar\").get(\"field\") or string-keyed access on a scalar node.","commonSituations":"The .pkl schema changed a nested object into a scalar (or vice versa) while the Java access code still expects an object; navigating config generically without checking node kind first; mis-typed generated accessor invoked on the wrong node.","solutions":["Call getRawValue() (or the typed value getter) on the node instead of requesting children.","Verify the node's structure against the .pkl source; update access code to match whether it is an object or scalar.","Regenerate typed config classes after schema changes.","Use instanceof/Config subclass checks (CompositeConfig vs LeafConfig) before navigating children."],"exampleFix":"// before\nObject child = leafConfig.getChild(\"name\"); // leaf has no children\n// after\nObject value = leafConfig.getRawValue();\nif (value instanceof Map<?,?> map) {\n  Object child = map.get(\"name\");\n}","handlingStrategy":"type-guard","validationCode":"// check node kind before navigating children\nif (node instanceof LeafConfig) {\n  Object value = ((LeafConfig) node).getRawValue();\n  // treat as scalar; do not call getChild\n}","typeGuard":"static boolean isLeaf(Config node) {\n  return node instanceof LeafConfig;\n}","tryCatchPattern":"try {\n  return node.getChild(name);\n} catch (NoSuchChildException e) {\n  if (node instanceof LeafConfig leaf) {\n    return leaf.getRawValue(); // caller actually wanted the scalar\n  }\n  throw e;\n}","preventionTips":["Regenerate typed accessors after any schema change that converts objects to scalars","Check node type (Composite vs Leaf vs Map) before generic tree navigation","Keep .pkl module and generated Java code in version lockstep","Prefer generated accessors over reflective/string-based child lookups"],"tags":["config","pkl","tree-navigation","scalar","missing-child"],"backgroundTag":"config-type-mismatch","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}