pentaho/pentaho-kettle · error · KettleXMLException

JobMeta.Exception.ErrorReadingFromXMLFile

Error message

JobMeta.Exception.ErrorReadingFromXMLFile

What it means

JobMeta.loadXML from file: after parsing the document, if the <job> root node (XML_TAG) is absent, doc is non-null but jobnode is effectively null/unusable and this message (plus the file name) is thrown as a KettleXMLException. It means the file exists and parses as XML but is not a Pentaho job document.

Solutions

  1. Verify the file's root element is <job>; if it is <transformation> you are loading a .ktr with the wrong loader.
  2. Re-export or restore the .kjb from backup/version control if it is truncated.
  3. Open the file in a text editor and confirm it starts with <?xml ...?><job> and is complete to </job>.
  4. Load via Spoon to see a friendlier diagnostic, then re-save.
  5. Check you are not passing an archive (zip) path instead of the extracted job XML.

Example fix

// before: loading a transformation as a job
JobMeta jobMeta = new JobMeta();
jobMeta.loadXML("etl.ktr", null, repo, metaStore, null); // not a <job> doc
// after
if (isTransformationFile("etl.ktr")) {
  TransMeta transMeta = new TransMeta("etl.ktr");
} else {
  JobMeta jobMeta = new JobMeta("etl.kjb", repo, metaStore, null);
}
Defensive patterns

Strategy: validation

Validate before calling

Document doc = XMLHandler.loadXMLFile(new File(fileName));
if (doc == null || XMLHandler.getSubNode(doc, "job") == null) {
  throw new IllegalArgumentException(fileName + " is not a job XML document (missing <job> root)");
}

Try / catch

try {
  jobMeta.loadXML(fname, rep, metaStore, prompter);
} catch (KettleXMLException e) {
  if (e.getMessage().contains("ErrorReadingFromXMLFile") || e.getMessage().contains(fname)) {
    throw new IllegalArgumentException("Not a valid .kjb file: " + fname, e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling JobMeta load-from-file with a file that parses to a DOM whose root is not <job> — e.g. passing a .ktr transformation, an export archive member, a configuration file, or a truncated .kjb missing its root element.

Common situations: Wrong file passed to the loader (transformation vs job); file extension renamed but content changed; partially downloaded/truncated .kjb; XML with wrong namespace or an extra wrapper root added by export tools.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13). Data as JSON: /api/errors/e221dfb0567b74df. Report an issue: GitHub.

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/job/JobMeta.java:885

   * @param fname The filename to load as a job
   * @param rep   The repository to bind againt, null if there is no repository available.
   * @throws KettleXMLException
   */
  public JobMeta( Bowl bowl, VariableSpace parentSpace, String fname, Repository rep, IMetaStore metaStore,
      OverwritePrompter prompter ) throws KettleXMLException {
    this.initializeVariablesFrom( parentSpace );
    this.metaStore = metaStore;
    setBowl( bowl );
    try {
      // OK, try to load using the VFS stuff...
      Document doc = XMLHandler.loadXMLFile( KettleVFS.getInstance( bowl ).getFileObject( fname, this ) );
      if ( doc != null ) {
        // The jobnode
        Node jobnode = XMLHandler.getSubNode( doc, XML_TAG );

        loadXML( jobnode, fname, rep, metaStore, false, prompter );
      } else {
        throw new KettleXMLException(
            BaseMessages.getString( PKG, "JobMeta.Exception.ErrorReadingFromXMLFile" ) + fname );
      }
    } catch ( Exception e ) {
      throw new KettleXMLException(
          BaseMessages.getString( PKG, "JobMeta.Exception.UnableToLoadJobFromXMLFile" ) + fname + "]", e );
    }
  }

  /**
   * Instantiates a new job meta.
   *
   * @param inputStream the input stream
   * @param rep         the rep
   * @param prompter    the prompter
   * @throws KettleXMLException the kettle xml exception
   */
  public JobMeta( InputStream inputStream, Repository rep, OverwritePrompter prompter ) throws KettleXMLException {
    this();

View on GitHub (pinned to f3058517a1)