apple/pkl · error · VmException

invalidXmlName

invalidXmlName

Error message

invalidXmlName

What it means

XML element or attribute names must be valid XML names (per the XML Name production validated by the renderer's validator). validateName throws an evaluation error with code invalidXmlName when a rendered element or attribute name fails validation.

Solutions

  1. Rename the element/attribute to a valid XML name (letters, digits, hyphens, underscores, periods; must not start with a digit or punctuation).
  2. Sanitize programmatic names before rendering (strip/replace invalid characters, prefix if starting with a digit).
  3. Use a fixed literal tag name and put the dynamic value in an attribute or text content instead.

Example fix

// before
new XmlElement { name = "123 item"; ... }
// after
new XmlElement { name = "item_123"; ... }
Defensive patterns

Strategy: validation

Validate before calling

boolean isValidXmlName(String name) {
  return name != null && name.matches("[:_A-Za-z][:\-._A-Za-z0-9]*");
}

Try / catch

try { renderer.render(doc); } catch (EvalException e) { if (e.getMessage().contains("invalidXmlName")) { /* sanitize and retry */ } }

Prevention

When it happens

Trigger: Rendering an XmlElement (or one of its properties/entries) whose tag name or attribute name contains spaces, starts with a digit, or contains characters not allowed in XML names; validateName is called for both element names and attribute names from writeXmlElement.

Common situations: Generating tags from user data or identifiers that contain hyphens in the wrong place, spaces, or leading digits; using a property name as a tag without sanitizing it; locale-formatted or templated names.

Related errors


AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08). Data as JSON: /api/errors/d28b07755a687ae0. Report an issue: GitHub.

Appendix: source

Thrown at pkl-core/src/main/java/org/pkl/core/stdlib/xml/RendererNodes.java:466

            .forceAndIterateMemberValues(
                (key, member, value) -> {
                  if (member.isElement()) doVisitElement(value);
                  return true;
                });
      } else {
        visit(content);
      }

      decreaseIndent();
      if (prevLineNumber < lineNumber) startNewLine();

      builder.append("</").append(name).append(">");
    }

    private void validateName(String name, String kind) {
      if (validator.isValidName(name)) return;

      throw new VmExceptionBuilder().evalError("invalidXmlName", version, kind, name).build();
    }

    private void startNewLine() {
      if (builder.isEmpty()) return;

      lineNumber += 1;
      builder.append(LINE_BREAK).append(currIndent);
    }
  }

  private static boolean isBlockFormat(VmObjectLike object) {
    return (Boolean) VmUtils.readMember(object, Identifier.IS_BLOCK_FORMAT);
  }
}

View on GitHub (pinned to f3efcbfc9b)