{"record":{"id":"2a5bbdb3b1fa8296","repo":"pentaho/pentaho-kettle","slug":"jobtrans-exception-missingtransfilename","errorCode":null,"errorMessage":"JobTrans.Exception.MissingTransFileName","messagePattern":"JobTrans\\.Exception\\.MissingTransFileName","errorType":"exception","errorClass":"KettleException","httpStatus":null,"severity":"error","filePath":"engine/src/main/java/org/pentaho/di/base/MetaFileLoaderImpl.java","lineNumber":373,"sourceCode":"    if ( hasUnresolvedFilenamePlaceholders( realFilename ) && space != null && tmpSpace != null && space != tmpSpace ) {\n      realFilename = tmpSpace.environmentSubstitute( filename );\n    }\n\n    return realFilename;\n  }\n\n  boolean hasUnresolvedFilenamePlaceholders( String filename ) {\n    return filename != null && ( filename.contains( \"${\" ) || filename.contains( \"%%\" ) );\n  }\n\n  private T getMetaFromRepository( Bowl bowl, Repository rep, CurrentDirectoryResolver r, String metaPath, VariableSpace tmpSpace )\n    throws KettleException {\n    String realName = \"\";\n    String realDirectory = \"/\";\n\n    if ( StringUtils.isBlank( metaPath ) ) {\n      if ( isTransMeta() ) {\n        throw new KettleException(\n          BaseMessages.getString( persistentClass, \"JobTrans.Exception.MissingTransFileName\" ) );\n      } else {\n        throw new KettleException(\n          BaseMessages.getString( persistentClass, \"JobJob.Exception.MissingJobFileName\" ) );\n      }\n    }\n\n    int index = metaPath.lastIndexOf( RepositoryFile.SEPARATOR );\n    if ( index != -1 ) {\n      realName = metaPath.substring( index + 1 );\n      realDirectory = index == 0 ? RepositoryFile.SEPARATOR : metaPath.substring( 0, index );\n    }\n    realDirectory = r.normalizeSlashes( realDirectory );\n\n    RepositoryDirectoryInterface repositoryDirectory = rep.loadRepositoryDirectoryTree().findDirectory( realDirectory );\n    if ( repositoryDirectory == null ) {\n      throw new KettleException( \"Unable to find repository directory [\" + Const.NVL( realDirectory, \"\" ) + \"]\" );\n    }","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/pentaho/pentaho-kettle/blob/f3058517a153da500bf4551f46d79b91bf8ec552/engine/src/main/java/org/pentaho/di/base/MetaFileLoaderImpl.java#L355-L391","documentation":"Thrown by MetaFileLoaderImpl.getMetaFromRepository when a transformation is configured to load from a repository but the meta path (repository path + object name) is blank or null. The loader cannot construct a repository lookup without a path, so it fails fast with the JobTrans 'missing transformation file name' message. It guards the TransMeta branch of the blank-metaPath check in getMetaFromRepository, reached via getMetaForEntry.","triggerScenarios":"Calling getMetaForEntry/getMetaFromRepository with specificationMethod=REPOSITORY_BY_NAME (repository-based resolution) while metaPath resolves to null or whitespace — typically when the transformation filename/path field was never set or an ${VARIABLE} in the path resolved to an empty string.","commonSituations":"Transformation executor/mapping steps where the 'Transformation' path field was left blank; a variable like ${INTERNAL_TRANS_PATH} unset in the run environment so environmentSubstitute yields empty; metadata exported/imported without the repository path populated; calling the loader API programmatically with an empty path string.","solutions":["Set the transformation's repository path (metaPath / filename field, e.g. '/home/admin/myTrans') on the step meta before executing.","If the path uses variables, define those variables in the run configuration, job parameters, or kettle.properties so substitution yields a non-empty value.","Verify the step is configured for the intended specification method: switch to FILENAME with a valid .ktr path if you meant to load from a file rather than the repository.","Guard callers: check StringUtils.isBlank(metaPath) before invoking getMetaForEntry and surface a clear validation message."],"exampleFix":"// before\nJobTransMeta meta = new JobTransMeta(); // repository path never set\nloader.getMetaForEntry(bowl, rep, metaStore, space);\n\n// after\nstepMeta.setTransName(\"myTrans\");\nstepMeta.setDirectory(\"/home/admin\"); // or metaPath = \"/home/admin/myTrans\"\nif (StringUtils.isNotBlank(metaPath)) {\n  loader.getMetaForEntry(bowl, rep, metaStore, space);\n}","handlingStrategy":"validation","validationCode":"// Java caller, before invoking the loader\nif (StringUtils.isBlank(stepMeta.getMetaPath())) {\n  throw new IllegalArgumentException(\n    \"Transformation repository path is blank; set the /dir/name path for the child transformation\");\n}","typeGuard":"boolean hasRepositoryPath(JobTransMeta m) {\n  return m != null && StringUtils.isNotBlank(m.getMetaPath());\n}","tryCatchPattern":"try {\n  T meta = loader.getMetaForEntry(bowl, rep, metaStore, space);\n} catch (KettleException e) {\n  if (String.valueOf(e.getMessage()).contains(\"MissingTransFileName\")) {\n    throw new ConfigurationException(\"Child transformation path not configured: \" + stepName, e);\n  }\n  throw e;\n}","preventionTips":["Always populate the repository path field on transformation-executor/mapping steps; validate job metadata before deployment.","Audit ${VARIABLE} usage in paths and ensure they are defined in run configurations or kettle.properties.","Add a startup smoke test that resolves every child-transformation path with environmentSubstitute and fails fast on blanks."],"tags":["kettle","pdi","repository","missing-configuration"],"backgroundTag":"missing-required-argument","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"}