{"record":{"id":"bb8eafa7febde34a","repo":"pentaho/pentaho-kettle","slug":"unable-to-close-file-filename","errorCode":null,"errorMessage":"Unable to close file '\" + filename + \"'","messagePattern":"Unable to close file '\" \\+ filename \\+ \"'","errorType":"exception","errorClass":"KettleXMLException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/trans/TransMeta.java","lineNumber":6604,"sourceCode":"   * @param filename\n   *          The filename to save to\n   * @throws KettleXMLException\n   *           in case something goes wrong.\n   */\n  public void writeXML( String filename ) throws KettleXMLException {\n    FileOutputStream fos = null;\n    try {\n      fos = new FileOutputStream( filename );\n      fos.write( XMLHandler.getXMLHeader().getBytes( Const.XML_ENCODING ) );\n      fos.write( getXML().getBytes( Const.XML_ENCODING ) );\n    } catch ( Exception e ) {\n      throw new KettleXMLException( \"Unable to save to XML file '\" + filename + \"'\", e );\n    } finally {\n      if ( fos != null ) {\n        try {\n          fos.close();\n        } catch ( IOException e ) {\n          throw new KettleXMLException( \"Unable to close file '\" + filename + \"'\", e );\n        }\n      }\n    }\n  }\n\n  /**\n   * Checks whether the transformation has repository references.\n   *\n   * @return true if the transformation has repository references, false otherwise\n   */\n  public boolean hasRepositoryReferences() {\n    for ( StepMeta stepMeta : steps ) {\n      if ( stepMeta.getStepMetaInterface().hasRepositoryReferences() ) {\n        return true;\n      }\n    }\n    return false;\n  }","sourceCodeStart":6586,"sourceCodeEnd":6622,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/trans/TransMeta.java#L6586-L6622","documentation":"In TransMeta.saveToKtr, the finally block closes the FileOutputStream; if fos.close() throws IOException it is wrapped in KettleXMLException 'Unable to close file <filename>'. The bytes may already be on disk but the file handle could not be cleanly released, so the file may be incomplete or unlocked only later.","triggerScenarios":"saveToKtr() reaching the finally clause where fos.close() throws IOException — typically OS-level flush failure (disk full at flush time), stream already closed, or underlying file system glitch.","commonSituations":"Disk filled up between write and close so buffered bytes cannot flush; file locked by another process/AV scanner; saving to a network share that dropped mid-write.","solutions":["Check the wrapped IOException cause; verify disk space, since close flushes remaining bytes.","Save to a local temp file and move/replace the target atomically after a successful close.","Retry the save after excluding the path from AV/indexing lockers.","Prefer Java 7+ try-with-resources semantics or upgrade PDI so close is handled without masking the primary error."],"exampleFix":"// before\ntransMeta.saveToKtr(\"/mnt/share/mytrans.ktr\"); // flaky network share\n// after\nFile tmp = File.createTempFile(\"mytrans\", \".ktr\");\ntransMeta.saveToKtr(tmp.getAbsolutePath());\nFiles.move(tmp.toPath(), Paths.get(\"/mnt/share/mytrans.ktr\"),\n  StandardCopyOption.REPLACE_EXISTING);","handlingStrategy":"fallback","validationCode":"File target = new File(filename);\nif (target.getFreeSpace() < 1_000_000L) throw new IllegalStateException(\"Low disk space before save\");","typeGuard":null,"tryCatchPattern":"try {\n  transMeta.saveToKtr(filename);\n} catch (KettleXMLException e) {\n  if (String.valueOf(e.getCause()).contains(\"close\")) {\n    // save to temp then atomic move, or retry after checking disk space\n  }\n}","preventionTips":["Save to a local temp file and atomically move into place","Monitor disk space on save targets","Avoid saving directly to flaky network shares or AV-scanned directories"],"tags":["kettle","file-write","io","close-failure"],"backgroundTag":"file-write-failed","analyzedSha":"f3058517a153da500bf4551f46d79b91bf8ec552","analyzedAt":"2026-09-13T14:04:16.340Z","contentChangedAt":"2026-09-13T14:04:16.340Z","schemaVersion":2},"datasetVersion":"2026-09-20T23:17:15.980Z"}