pentaho/pentaho-kettle · error · KettleException

ScriptMeta.Exception.UnableToSaveStepInfo

Error message

ScriptMeta.Exception.UnableToSaveStepInfo

What it means

saveRep() persists Script step metadata (scripts, fields, types, lengths, precision, replace flags) as step attributes. Any repository exception during save is wrapped in KettleException 'UnableToSaveStepInfo' plus the step's ObjectId.

Solutions

  1. Read the nested cause (Caused by) to identify the database-level failure.
  2. Reconnect/retry the save after restoring repository database connectivity.
  3. Check repository user permissions — the account needs write access to step attributes.
  4. Save the transformation as XML locally as a workaround while fixing the repository.

Example fix

// before: saving while DB is read-only
rep.saveStepAttribute(id_transformation, id_step, i, "field_replace", replace[i]);
// after: ensure a writable connection first
if (!rep.getConnection().isReadOnly()) { rep.saveStepAttribute(...); }
Defensive patterns

Strategy: retry

Validate before calling

// Check writability before saving
if (rep.getConnection().isReadOnly()) throw new IllegalStateException("repository read-only");

Try / catch

try { saveTransformation(); } catch (KettleException e) {
  if (e.getCause() instanceof java.sql.SQLException) { reconnectAndRetryOnce(); }
  else { exportToXmlLocally(); throw e; }
}

Prevention

When it happens

Trigger: Saving a transformation to the repository when writing R_STEP_ATTRIBUTE rows fails — DB connection dropped, constraint violation, read-only database, or oversized attribute values.

Common situations: Repository database disk full or read-only; network hiccup mid-save; concurrent modification of the same transformation by two users.

Related errors


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

Appendix: source

Thrown at engine/src/main/java/org/pentaho/di/trans/steps/script/ScriptMeta.java:410

  public void saveRep( Repository rep, IMetaStore metaStore, ObjectId id_transformation, ObjectId id_step ) throws KettleException {
    try {
      for ( int i = 0; i < jsScripts.length; i++ ) {
        rep.saveStepAttribute( id_transformation, id_step, i, JSSCRIPT_TAG_NAME, jsScripts[i].getScriptName() );
        rep.saveStepAttribute( id_transformation, id_step, i, JSSCRIPT_TAG_SCRIPT, jsScripts[i].getScript() );
        rep.saveStepAttribute( id_transformation, id_step, i, JSSCRIPT_TAG_TYPE, jsScripts[i].getScriptType() );
      }

      for ( int i = 0; i < fieldname.length; i++ ) {
        rep.saveStepAttribute( id_transformation, id_step, i, "field_name", fieldname[i] );
        rep.saveStepAttribute( id_transformation, id_step, i, "field_rename", rename[i] );
        rep.saveStepAttribute( id_transformation, id_step, i, "field_type",
          ValueMetaFactory.getValueMetaName( type[i] ) );
        rep.saveStepAttribute( id_transformation, id_step, i, "field_length", length[i] );
        rep.saveStepAttribute( id_transformation, id_step, i, "field_precision", precision[i] );
        rep.saveStepAttribute( id_transformation, id_step, i, "field_replace", replace[i] );
      }
    } catch ( Exception e ) {
      throw new KettleException( BaseMessages.getString( PKG, "ScriptMeta.Exception.UnableToSaveStepInfo" )
        + id_step, e );
    }
  }

  public void check( List<CheckResultInterface> remarks, TransMeta transMeta, StepMeta stepMeta,
    RowMetaInterface prev, String[] input, String[] output, RowMetaInterface info, VariableSpace space,
    Repository repository, IMetaStore metaStore ) {
    boolean error_found = false;
    String error_message = "";
    CheckResult cr;

    ScriptEngine jscx;
    Bindings jsscope;
    CompiledScript jsscript;

    jscx = createNewScriptEngine( stepMeta.getName() );
    jsscope = jscx.getBindings( ScriptContext.ENGINE_SCOPE );

View on GitHub (pinned to f3058517a1)