pentaho/pentaho-kettle · error · java.lang.RuntimeException
RuntimeException wrapping clone failure (no message; cause…
Error message
RuntimeException wrapping clone failure (no message; cause is the KettleException from RowMeta copy)
What it means
RowMeta.clone() copies the row metadata via the copy constructor new RowMeta(this, null) under the read lock; if that copy throws any KettleException (e.g. a cloned ValueMeta fails), it is rethrown as an unmodifiable RuntimeException with no message. The meaningful cause is the wrapped KettleException from RowMeta's copy logic.
Solutions
- Unwrap and inspect getCause() - the KettleException (and its cause) names the failing value meta
- Identify the offending field's ValueMetaInterface and rebuild/normalize it before cloning
- Call cloneIntersection or copy via new RowMeta(original) explicitly to localize the failure
- Update PDI to a version fixing the specific ValueMeta clone bug if the cause points to a known valueMeta
Example fix
// before
RowMeta copy = (RowMeta) inputRowMeta.clone(); // bare RuntimeException, no message
// after
try {
RowMeta copy = (RowMeta) inputRowMeta.clone();
} catch ( RuntimeException e ) {
throw new KettleException( "Failed to clone row metadata", e.getCause() ); // preserve real cause
} Defensive patterns
Strategy: try-catch
Validate before calling
if ( rowMeta == null || rowMeta.isEmpty() ) {
throw new IllegalStateException("no row metadata to clone");
} Type guard
static boolean isCloneSafe(RowMeta rm) {
return rm != null && rm.size() > 0
&& java.util.Arrays.stream(rm.getValueMetaList()).allMatch(java.util.Objects::nonNull);
} Try / catch
try {
RowMeta copy = (RowMeta) rowMeta.clone();
} catch ( RuntimeException e ) {
// no message on purpose: the KettleException is the cause
throw new KettleException("RowMeta clone failed", e.getCause());
} Prevention
- Always unwrap getCause() - the RuntimeException itself carries no message
- Mutate RowMeta only through thread-safe accessors; never share mutable ValueMeta across threads
- Validate value metadata after deserializing from repository or ktr files
- Keep PDI patched - several ValueMeta clone bugs were fixed in later versions
When it happens
Trigger: Calling rowMeta.clone() (often via row.clone() in steps) when the underlying value meta list contains a ValueMeta whose clone/copy fails - e.g. corrupt or exotic value metadata, or an internal copy error inside the RowMeta(ValueMetaInterface...) constructor.
Common situations: Cloning row metadata in long-running transformations where a custom/patched value meta implementation misbehaves; concurrency issues if metadata was mutated without the lock; corrupted serialized metadata deserialized from a repository/ktr.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Clone not supported for
- Clone not supported for
- Clone not supported for
- KettleValueException wrapping KettlePluginException from…
- Problem with clone row detected in RowMetaAndData
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/d0a9289e386379fb.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/core/row/RowMeta.java:89
.cloneValueMeta( valueMetaInterface, targetType == null ? valueMetaInterface.getType() : targetType ) );
}
this.needRealClone = rowMeta.needRealClone;
}
private RowMeta( List<ValueMetaInterface> valueMetaList, RowMetaCache rowMetaCache ) {
lock = new ReentrantReadWriteLock();
this.cache = rowMetaCache;
this.valueMetaList = valueMetaList;
this.needRealClone = new ArrayList<>();
}
@Override
public RowMeta clone() {
lock.readLock().lock();
try {
return new RowMeta( this, null );
} catch ( Exception e ) {
throw new RuntimeException( e );
} finally {
lock.readLock().unlock();
}
}
/**
* This method copies the row metadata and sets all values to the specified type (usually String)
*
* @param targetType The target type
* @return The cloned metadata
* @throws if the target type could not be loaded from the plugin registry
*/
@Override
public RowMetaInterface cloneToType( int targetType ) throws KettleValueException {
lock.readLock().lock();
try {
return new RowMeta( this, targetType );
} catch ( KettlePluginException e ) {View on GitHub (pinned to f3058517a1)