{"record":{"id":"53b7f3b7e93e1637","repo":"pentaho/pentaho-kettle","slug":"the-number-of-job-entry-copies-read","errorCode":null,"errorMessage":"The number of job entry copies read [","messagePattern":"The number of job entry copies read \\[","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"plugins/pur/core/src/main/java/org/pentaho/di/repository/pur/JobDelegate.java","lineNumber":239,"sourceCode":"      copy.setNr( (int) copyNode.getProperty( PROP_NR ).getLong() );\n      int x = (int) copyNode.getProperty( PROP_GUI_LOCATION_X ).getLong();\n      int y = (int) copyNode.getProperty( PROP_GUI_LOCATION_Y ).getLong();\n      copy.setLocation( x, y );\n      copy.setDrawn( copyNode.getProperty( PROP_GUI_DRAW ).getBoolean() );\n      copy.setLaunchingInParallel( copyNode.getProperty( PROP_PARALLEL ).getBoolean() );\n\n      // Read the job entry group attributes map\n      if ( jobEntry instanceof JobEntryBase ) {\n        AttributesMapUtil.loadAttributesMap( copyNode, (JobEntryBase) jobEntry );\n      }\n\n      loadAttributesMap( copyNode, copy );\n\n      jobMeta.addJobEntry( copy );\n    }\n\n    if ( jobMeta.getJobCopies().size() != nrCopies ) {\n      throw new KettleException( \"The number of job entry copies read [\" + jobMeta.getJobCopies().size()\n          + \"] was not the number we expected [\" + nrCopies + \"]\" );\n    }\n\n    // Read the notes...\n    //\n    DataNode notesNode = rootNode.getNode( NODE_NOTES );\n    int nrNotes = (int) notesNode.getProperty( PROP_NR_NOTES ).getLong();\n    for ( DataNode noteNode : notesNode.getNodes() ) {\n      String xml = getString( noteNode, PROP_XML );\n      jobMeta\n          .addNote( new NotePadMeta( XMLHandler.getSubNode( XMLHandler.loadXMLString( xml ), NotePadMeta.XML_TAG ) ) );\n    }\n    if ( jobMeta.nrNotes() != nrNotes ) {\n      throw new KettleException( \"The number of notes read [\" + jobMeta.nrNotes()\n          + \"] was not the number we expected [\" + nrNotes + \"]\" );\n    }\n\n    // Read the hops...","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/plugins/pur/core/src/main/java/org/pentaho/di/repository/pur/JobDelegate.java#L221-L257","documentation":"JobDelegate.dataNodeToElement reads job entry copies from the repository DataNode, adds each to jobMeta, then asserts that the number of job copies in the reconstructed JobMeta equals the expected nrCopies stored on the node. A mismatch means the stored job entry copy list is incomplete or inconsistent with its recorded count, so the delegate refuses to load a partially or corruptly deserialized job.","triggerScenarios":"Loading a job from a Pentaho repository whose stored DataNode contains fewer (or more) job-entry copy child nodes than the persisted nrCopies attribute — e.g. interrupted save, concurrent modification, repository serialization/version mismatch between writer and reader.","commonSituations":"Repository corruption after a failed or aborted save; two PDI clients writing the same job concurrently; restoring content exported from a different PDI/Pentaho version; manual database edits on the repository content tables.","solutions":["Re-save or restore the job from version control / a backup — the stored copy nodes are inconsistent.","Compare jobMeta.getJobCopies().size() to the stored nrCopies by dumping the job's DataNode; identify the missing copy nodes.","Upgrade both PDI client and Pentaho server to matching versions to rule out serialization drift.","Clear and republish the affected job (delete it from the repository and re-import from a known-good export).","If loading programmatically, catch KettleException and fall back to re-downloading or re-creating the job metadata."],"exampleFix":"// before\nJobMeta jobMeta = (JobMeta) repository.loadJob(jobId, null).loadAll(); // throws on count mismatch\n// after\ntry {\n  jobMeta = (JobMeta) repository.loadJob(jobId, null).loadAll();\n} catch (KettleException e) {\n  if (e.getMessage().startsWith(\"The number of job entry copies read\")) {\n    jobMeta = restoreJobFromBackup(jobId);\n  } else {\n    throw e;\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  JobMeta jobMeta = (JobMeta) repository.loadJob(jobId, null).loadAll();\n} catch (KettleException e) {\n  if (e.getMessage().startsWith(\"The number of job entry copies read\")) {\n    // repository content inconsistent -> restore from backup/re-export\n  } else {\n    throw e;\n  }\n}","preventionTips":["Avoid concurrent edits of the same job by multiple PDI clients.","Always let PDI save jobs; never edit repository storage manually.","Keep PDI client and Pentaho server on matching versions.","Keep export (.kjb) backups so corrupt jobs can be re-imported."],"tags":["pentaho","kettle","repository","corruption","deserialization"],"backgroundTag":"internal-invariant-violation","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"}