pentaho/pentaho-kettle · error · MissingResourceException
Unable to find properties file
Error message
Unable to find properties file '${resourceName}': ${e} What it means
GlobalMessageUtil.getBundle() wraps MissingResourceException thrown by ResourceBundle.getBundle() with a clearer message including the properties file name. The underlying cause is that the locale-specific resource bundle (a .properties file on the classpath for packagePath) could not be located by the GlobalResourceBundleControl. It is rethrown as a MissingResourceException with the original exception appended.
Solutions
- Verify the .properties file exists at the exact package path for the requested locale (or a default file) inside the jar/classpath
- Log/inspect the wrapped cause (e.toString()) to see the original MissingResourceException baseName/locale
- Correct the packagePath argument passed to getBundle
- Ensure the resourceClass's classloader can load the resource (check plugin packaging/classloader setup)
- Install the appropriate language pack or fall back to a default locale
Example fix
// before ResourceBundle bundle = GlobalMessageUtil.getBundle( MyClass.class, "org/wrong/path/messages", locale, true ); // after ResourceBundle bundle = GlobalMessageUtil.getBundle( MyClass.class, "org/correct/path/messages/messages", locale, true );
Defensive patterns
Strategy: try-catch
Validate before calling
ClassLoader cl = MyClass.class.getClassLoader();
String path = packagePath + "_" + locale + ".properties";
if ( cl.getResource( path ) == null && cl.getResource( packagePath + ".properties" ) == null ) {
throw new IllegalStateException( "Bundle resource missing on classpath: " + packagePath );
} Type guard
boolean bundleExists = MyClass.class.getClassLoader().getResource( packagePath + ".properties" ) != null;
Try / catch
try {
bundle = GlobalMessageUtil.getBundle( cls, packagePath, locale, true );
} catch ( MissingResourceException e ) {
log.warn( "i18n bundle missing, using default locale", e );
bundle = GlobalMessageUtil.getBundle( cls, packagePath, Locale.ENGLISH, true );
} Prevention
- Verify properties files are packaged in the jar after build
- Always ship a default locale-less properties file
- Test getBundle for each supported locale in CI
When it happens
Trigger: Calling getBundle(resourceClass, packagePath, locale, fallbackOnRoot) when no .properties file matching the base name exists for the requested locale (including any fallback), or the resourceClass's classloader cannot see the properties file.
Common situations: A plugin jar is missing its messages_<locale>.properties files; a typo in the package path passed to getBundle; custom language packs not installed; classloader isolation (e.g. in a webapp or Karaf) hides the bundle from the plugin classloader.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Unable to find properties file for package
- Unable to find properties file
- Cannot find WSDL file: + _wsdlName
- Could not get repository instance
- Could not initialize from codeSnippets.xml
AI-assisted analysis of pentaho/pentaho-kettle@f3058517a1 (2026-09-13).
Data as JSON: /api/errors/6717a81223880cc0.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/pentaho/di/i18n/GlobalMessageUtil.java:334
* @param packagePath
* @param resourceClass
* @param fallbackOnRoot if true, and a {@link ResourceBundle} cannot be found for the requested {@link Locale}, falls
* back on the ROOT {@link Locale}
* @return a {@link ResourceBundle} corresponding to the given {@link Locale} package and resource class
*/
public static ResourceBundle getBundle( final Locale locale, final String packagePath, final Class<?> resourceClass,
final boolean fallbackOnRoot ) {
final GlobalMessageControl control = new GlobalMessageControl( fallbackOnRoot );
final String resourceName = control.toResourceName( control.toBundleName( packagePath, locale ), "properties" );
ResourceBundle bundle;
try {
bundle = ResourceBundle.getBundle( packagePath, locale, resourceClass.getClassLoader(),
new GlobalMessageControl( fallbackOnRoot ) );
} catch ( final MissingResourceException e ) {
final StringBuilder msg = new StringBuilder();
msg.append( "Unable to find properties file '" ).append( resourceName ).append( "': " ).append( e.toString() );
throw new MissingResourceException( msg.toString(), resourceClass.getName(), packagePath );
}
return bundle;
}
/**
* Returns a string corresponding to the locale (Example: "en", "en_US").
*
* @param locale The {@link Locale} whose string representation it being returned
* @return a string corresponding to the locale (Example: "en", "en_US").
*/
protected static String getLocaleString( Locale locale ) {
final StringBuilder localeString = new StringBuilder();
if ( locale != null && !StringUtils.isBlank( locale.getLanguage() ) ) {
if ( !StringUtils.isBlank( locale.getCountry() ) ) {
// force language to be lower case and country to be upper case
localeString.append( locale.getLanguage().toLowerCase() ).append( '_' ).append(
locale.getCountry().toUpperCase() );
} else {View on GitHub (pinned to f3058517a1)