Skip to content

Bundle_en.properties crashes Dataverse on startup #12487

Description

@DonRichards

What steps does it take to reproduce the issue?

  • When does this issue occur?

When dataverse.lang.directory is configured and a Bundle_en.properties file exists in that directory (even an empty file), Dataverse fails to start after a restart or redeploy.

  • Which page(s) does it occurs on?

Not page-specific; Dataverse fails during application deployment/startup. No pages are reachable.

  • What happens?
  1. Deploy Dataverse 6.9 on Payara 6.2025.10 - verify it starts normally.
  2. Set the JVM option:
    asadmin create-jvm-options -- "-Ddataverse.lang.directory=/usr/local/payara6/glassfish/domains/domain1/lang"
    
  3. Create the directory and an override file (content does not matter — even an empty file triggers the bug):
    mkdir -p /usr/local/payara6/glassfish/domains/domain1/lang
    touch /usr/local/payara6/glassfish/domains/domain1/lang/Bundle_en.properties
    chown -R dataverse:dataverse /usr/local/payara6/glassfish/domains/domain1/lang
    
  4. Restart Payara:
    systemctl restart payara
    
  5. Dataverse fails to start with NullPointerException in PasswordValidatorServiceBean.<init>. The version API (/api/info/version) returns a Payara error page instead of JSON. Removing the file and restarting immediately resolves it.
  • To whom does it occur (all users, curators, superusers)?

All users — the application does not start at all.

  • What did you expect to happen?

Dataverse should start normally and use the keys in Bundle_en.properties as overrides for the English locale, as documented in the Installation Guide. This is the recommended upgrade-safe mechanism for text customizations.

Which version of Dataverse are you using?

  • Dataverse: 6.9 (build 2027-e2021d3)
  • Payara: 6.2025.10 (build 42)
  • Java: OpenJDK 17.0.19 (Red Hat)
  • OS: RHEL 8 (Rocky Linux 8)

Dataverse 6.10 likely affected as well (same code pattern present in the v6.10 source for GoodStrengthRule.java).

Any related open or closed issues to this bug report?

Not aware of any existing issues for this specific failure.

Screenshots:

Full stack trace from server.log:

[SEVERE] Exception while loading the app : EJB Container initialization error
java.lang.NullPointerException
  at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011)
  at java.base/java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006)
  at java.base/java.util.Properties.put(Properties.java:1301)
  at java.base/java.util.Properties.setProperty(Properties.java:229)
  at edu.harvard.iq.dataverse.validation.PasswordValidatorServiceBean.<init>(PasswordValidatorServiceBean.java:102)
  at edu.harvard.iq.dataverse.validation.__EJB31_Generated__PasswordValidatorServiceBean__Intf____Bean__.<init>(Unknown Source)
  at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
  ...
  at com.sun.ejb.containers.StatelessSessionContainer.initializeHome(StatelessSessionContainer.java:216)
  at com.sun.ejb.containers.StatelessContainerFactory.createContainer(StatelessContainerFactory.java:63)
  at org.glassfish.ejb.startup.EjbApplication.loadContainers(EjbApplication.java:225)

Root cause analysis:

GoodStrengthRule.java initializes static fields at class-load time by calling BundleUtil.getStringFromBundle():

static final String ERROR_CODE_GOODSTRENGTH = BundleUtil.getStringFromBundle("passwdVal.goodStrengthRule.errorCode");
static final String ERROR_MESSAGE_GOODSTRENGTH = BundleUtil.getStringFromBundle("passwdVal.goodStrengthRule.errorMsg");

When dataverse.lang.directory is set, BundleUtil attempts to load the ResourceBundle from the external directory during class loading. At this point during EJB container initialization, the resource bundle system is not fully available, so BundleUtil.getStringFromBundle() returns null. This null is then passed to Properties.setProperty() in PasswordValidatorServiceBean.<init> (line 102):

properties.setProperty(GoodStrengthRule.ERROR_CODE_GOODSTRENGTH, GoodStrengthRule.ERROR_MESSAGE_GOODSTRENGTH);

ConcurrentHashMap.put() (which backs Properties) does not allow null keys or values, hence the NPE.

Workaround:

Remove the JVM option to disable external bundle overrides entirely:

asadmin delete-jvm-options -- "-Ddataverse.lang.directory=/usr/local/payara6/glassfish/domains/domain1/lang"

This means text customizations cannot be externalized in an upgrade-safe way on 6.9.

Are you thinking about creating a pull request for this issue?

Happy to discuss, though the fix appears straightforward. The suggested (by my coding assistant) approach is to change GoodStrengthRule.java to lazy initialization so BundleUtil is not called during class loading:

class GoodStrengthRule extends LengthRule {

    static String getErrorCode() {
        return BundleUtil.getStringFromBundle("passwdVal.goodStrengthRule.errorCode");
    }

    static String getErrorMessage() {
        return BundleUtil.getStringFromBundle("passwdVal.goodStrengthRule.errorMsg");
    }

    @Override
    public RuleResult validate(PasswordData passwordData) {
        final RuleResult result = super.validate(passwordData);
        if (!result.isValid()) {
            result.getDetails().clear();
            result.getDetails().add(new RuleResultDetail(getErrorCode(), createRuleResultDetailParameters()));
        }
        return result;
    }
}

And add a null guard in PasswordValidatorServiceBean:

public PasswordValidatorServiceBean() {
    final Properties properties = PropertiesMessageResolver.getDefaultProperties();
    String errorCode = GoodStrengthRule.getErrorCode();
    String errorMessage = GoodStrengthRule.getErrorMessage();
    if (errorCode != null && errorMessage != null) {
        properties.setProperty(errorCode, errorMessage);
    }
    messageResolver = new PropertiesMessageResolver(properties);
}

This ensures BundleUtil is called at first validation use (when the application is fully initialized) rather than during class loading. I'm not a java developer and I have not tested this at all so I'm not sure how reasonable this suggestion is.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions