pentaho/pentaho-kettle · error · KettleException

ERROR_0003_Unable_To_Save_Job

ERROR_0003_Unable_To_Save_Job

Error message

JobEntryFileCompare.ERROR_0003_Unable_To_Save_Job

What it means

Thrown by JobEntryFileCompare.saveRep when persisting the entry's attributes (filename1, filename2, add_filename_result) to the repository fails. A KettleDatabaseException is wrapped in a KettleException with a localized message carrying the job id. It means the repository write for this entry did not commit.

Solutions

  1. Check repository DB connectivity and retry the save
  2. Verify the DB user has INSERT/UPDATE rights on r_jobentry_attribute
  3. Look at the wrapped KettleDatabaseException cause for the exact SQL error
  4. Close conflicting Spoon sessions holding locks on the same job
Defensive patterns

Strategy: try-catch

Validate before calling

// Pre-check repository writability
if (rep.isReadOnly()) { throw new IllegalStateException("repository is read-only"); }

Try / catch

try {
    jobMeta.saveRep(rep, metaStore, id_job);
} catch (KettleException e) {
    logError("Save failed: " + e.getMessage(), e);
    // keep the in-memory JobMeta so the user can retry or export to XML
}

Prevention

When it happens

Trigger: Calling JobMeta.saveRep (or Job.save) against a database repository when the underlying insert/update of job entry attributes fails: connection loss, constraint violation, read-only repository.

Common situations: Repository DB down or network blip during save; insufficient DB user privileges; transaction lock from another Spoon session editing the same job.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/job/entries/filecompare/JobEntryFileCompare.java:131

  public void loadRep( Repository rep, IMetaStore metaStore, ObjectId id_jobentry, List<DatabaseMeta> databases,
    List<SlaveServer> slaveServers ) throws KettleException {
    try {
      filename1 = rep.getJobEntryAttributeString( id_jobentry, "filename1" );
      filename2 = rep.getJobEntryAttributeString( id_jobentry, "filename2" );
      addFilenameToResult = rep.getJobEntryAttributeBoolean( id_jobentry, "add_filename_result" );
    } catch ( KettleException dbe ) {
      throw new KettleException( BaseMessages.getString(
        PKG, "JobEntryFileCompare.ERROR_0002_Unable_To_Load_Job_From_Repository", id_jobentry ), dbe );
    }
  }

  public void saveRep( Repository rep, IMetaStore metaStore, ObjectId id_job ) throws KettleException {
    try {
      rep.saveJobEntryAttribute( id_job, getObjectId(), "filename1", filename1 );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "filename2", filename2 );
      rep.saveJobEntryAttribute( id_job, getObjectId(), "add_filename_result", addFilenameToResult );
    } catch ( KettleDatabaseException dbe ) {
      throw new KettleException( BaseMessages.getString(
        PKG, "JobEntryFileCompare.ERROR_0003_Unable_To_Save_Job", id_job ), dbe );
    }
  }

  public String getRealFilename1() {
    return environmentSubstitute( getFilename1() );
  }

  public String getRealFilename2() {
    return environmentSubstitute( getFilename2() );
  }

  /**
   * Check whether 2 files have the same contents.
   *
   * @param file1
   *          first file to compare
   * @param file2

View on GitHub (pinned to f3058517a1)