{"record":{"id":"9abb712bc995088b","repo":"pentaho/pentaho-kettle","slug":"the-database-cache-contains-an-empty-row-we-can-t-save-this","errorCode":null,"errorMessage":"The database cache contains an empty row. We can't save this!","messagePattern":"The database cache contains an empty row\\. We can't save this!","errorType":"exception","errorClass":"KettleFileException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/pentaho/di/core/DBCache.java","lineNumber":192,"sourceCode":"      String filename = fileNameSupplier.get();\n      File file = new File( filename );\n      if ( !file.exists() || file.canWrite() ) {\n\n        try ( DataOutputStream dos =\n                new DataOutputStream( new BufferedOutputStream( new FileOutputStream( file ), 10000 ) ) ) {\n\n          int counter = 0;\n\n          for ( DBCacheEntry entry : cache.keySet() ) {\n            entry.write( dos );\n\n            // Save the corresponding row as well.\n            RowMetaInterface rowMeta = get( entry );\n            if ( rowMeta != null ) {\n              rowMeta.writeMeta( dos );\n              counter++;\n            } else {\n              throw new KettleFileException( \"The database cache contains an empty row. We can't save this!\" );\n            }\n          }\n          log.logDetailed( \"We wrote \" + counter + \" cached rows to the database cache!\" );\n        }\n      } else {\n        throw new KettleFileException( \"We can't write to the cache file: \" + filename );\n      }\n    } catch ( Exception e ) {\n      throw new KettleFileException( \"Couldn't write to the database cache\", e );\n    }\n  }\n\n  /**\n   * Create the database cache instance by loading it from disk\n   *\n   * @return the database cache instance.\n   */\n  @SuppressWarnings( \"squid:S00112\" )","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/core/src/main/java/org/pentaho/di/core/DBCache.java#L174-L210","documentation":"DBCache.saveCache() iterates cached entries and writes each RowMetaInterface to disk. If an entry's row metadata is null (entry exists in the map but has no row), it throws KettleFileException 'The database cache contains an empty row. We can't save this!' because a null row cannot be serialized. This guards cache-file integrity.","triggerScenarios":"Calling saveCache() (via savesCacheToDisk) while the in-memory cache contains a DBCacheEntry mapped to a null RowMetaInterface — typically from a race where an entry was inserted without its row, or code that cached a lookup before metadata was available.","commonSituations":"Concurrent access to the DB cache from multiple threads/steps where entries are added before rows; custom plugin code calling DBCache Fahne APIs incorrectly; a bug after deserializing a partially corrupt cache.","solutions":["Remove null-valued entries before saving (filter the cache map for null RowMetaInterface)","Synchronize access to the DBCache so entries are only added together with their rows","If triggered by a corrupt loaded cache, delete the cache file and restart so it rebuilds clean"],"exampleFix":"// before\nsaveCache(); // throws if any entry has null rowMeta\n// after\ncache.getMap().values().removeIf(Objects::isNull); // or guard inserts\nsaveCache();","handlingStrategy":"validation","validationCode":"// Before saving, prune entries with null rows\nmap.values().removeIf(Objects::isNull);","typeGuard":"boolean isCacheEntrySavable(DBCacheEntry e, RowMetaInterface row) { return e != null && row != null; }","tryCatchPattern":"try { cache.savesCacheToDisk(); } catch (KettleFileException e) { if (e.getMessage().contains(\"empty row\")) { /* clear cache and retry */ } else { throw e; } }","preventionTips":["Insert cache entries atomically (entry + row together)","Synchronize concurrent access to the DBCache map","Rebuild the cache from scratch if it was loaded from a suspect file"],"tags":["cache","file-write","state","pentaho-kettle"],"backgroundTag":"database-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"}