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

  1. Verify the .properties file exists at the exact package path for the requested locale (or a default file) inside the jar/classpath
  2. Log/inspect the wrapped cause (e.toString()) to see the original MissingResourceException baseName/locale
  3. Correct the packagePath argument passed to getBundle
  4. Ensure the resourceClass's classloader can load the resource (check plugin packaging/classloader setup)
  5. 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

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


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)