pentaho/pentaho-kettle · error · KettleException

Unable to write target file (ktr after injection) to file

Error message

Unable to write target file (ktr after injection) to file '{targetFilePath}'

What it means

Thrown by MetaInject.writeInjectedKtrToFs() (called from writeInjectedKtr) when writing the generated, injected .ktr XML to the target file throws an IOException. The step opens an output stream via KettleVFS, writes the XML header and the generatedTransMeta XML, and wraps any IOException in this KettleException. The injected transformation file is not produced when this happens.

Solutions

  1. Check the wrapped IOException in the log for the concrete filesystem cause
  2. Verify the target directory exists and the process user has write permission to targetFilePath
  3. Ensure the target .ktr is not locked/open elsewhere and there is free disk space
  4. Correct or clear the 'target file' option in the Meta Inject dialog if it points to an invalid VFS URI

Example fix

// before: non-existent output dir
meta.setTargetFilePath('file:///tmp/missing-dir/injected.ktr');
// after: ensure dir exists first
new java.io.File('/tmp/out').mkdirs();
meta.setTargetFilePath('file:///tmp/out/injected.ktr');
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check target writeability
java.io.File dir = new java.io.File('/tmp/out');
if (!dir.isDirectory()) dir.mkdirs();
java.io.File f = new java.io.File(dir, 'injected.ktr');
if (!f.canWrite() && f.exists()) throw new IllegalStateException('Target file not writable');

Type guard

boolean canWriteTarget(String vfsPath) {
  try (java.io.OutputStream os = new java.io.FileOutputStream(vfsPath.replaceAll('^file://',''), true)) {
    return os != null;
  } catch (IOException e) { return false; }
}

Try / catch

try {
  // run Meta Inject with target file set
} catch (KettleException e) {
  if (e.getMessage().startsWith('Unable to write target file')) {
    log.error('Check dir exists, permissions, disk space, file lock: ' + e.getCause(), e);
  } else throw e;
}

Prevention

When it happens

Trigger: The OutputStream obtained from KettleVFS.getOutputStream(targetFilePath, false) cannot be written to: the target directory does not exist, the file is locked, disk is full, or filesystem permissions deny writing.

Common situations: 'Show injected transformation' / debug output path pointing to a non-existent or read-only directory; target file open in another program (Windows lock); VFS path typo (bad scheme); insufficient user permissions; disk quota exceeded.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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

Appendix: source

Thrown at plugins/meta-inject/impl/src/main/java/org/pentaho/di/trans/steps/metainject/MetaInject.java:289

    OutputStream os = null;
    try {
      // don't clear all the clone's data before copying from the source object
      TransMeta generatedTransMeta = (TransMeta) data.transMeta.realClone( false );
      File injectedKtrFile = new File( targetFilePath );

      if ( injectedKtrFile == null ) {
        throw new IOException();
      } else {
        String transName = injectedKtrFile.getName().replace( ".ktr", "" );
        generatedTransMeta.setName( transName ); // set transname on injectedtrans to be same as filename w/o extension
      }

      os = KettleVFS.getInstance( getTransMeta().getBowl() ).getOutputStream( targetFilePath, false );
      os.write( XMLHandler.getXMLHeader().getBytes( Const.XML_ENCODING ) );
      os.write( generatedTransMeta.getXML().getBytes( Const.XML_ENCODING ) );
    } catch ( IOException e ) {
      throw new KettleException( "Unable to write target file (ktr after injection) to file '"
        + targetFilePath + "'", e );
    } finally {
      if ( os != null ) {
        try {
          os.close();
        } catch ( Exception e ) {
          throw new KettleException( e );
        }
      }
    }
  }

  /**
   * Writes the generated meta injection transformation to the repository. It is assumed that the repository
   * exists (user is connected).
   * @param targetFilePath the repo path to which to save the generated injection ktr
   * @throws KettleException
   */

View on GitHub (pinned to f3058517a1)