Configuration library for JVM languages using HOCON files
—
Exception handling in Typesafe Config provides a comprehensive hierarchy of runtime exceptions for different error conditions. All exceptions extend ConfigException and provide detailed context information for debugging and error recovery.
Base class for all configuration-related exceptions.
public abstract class ConfigException extends RuntimeException {
public ConfigException(String message);
public ConfigException(String message, Throwable cause);
public ConfigOrigin origin();
}Common Methods:
getMessage() - Human-readable error descriptiongetCause() - Underlying exception if applicableorigin() - Configuration origin where error occurredThrown when a required configuration path is not found.
public static class Missing extends ConfigException {
public String path();
}Usage Examples:
try {
String dbUrl = config.getString("database.url");
} catch (ConfigException.Missing e) {
String missingPath = e.path();
System.err.println("Missing required configuration: " + missingPath);
// Provide default or fail gracefully
String defaultUrl = "jdbc:h2:mem:default";
System.out.println("Using default database URL: " + defaultUrl);
}Thrown when a configuration path exists but has a null value.
public static class Null extends ConfigException.Missing {
// Inherits path() method from Missing
}Usage Examples:
try {
String apiKey = config.getString("api.key");
} catch (ConfigException.Null e) {
System.err.println("API key is explicitly set to null at: " + e.path());
// Handle null value scenario
} catch (ConfigException.Missing e) {
System.err.println("API key configuration is missing: " + e.path());
// Handle missing value scenario
}Thrown when requesting a value with an incompatible type.
public static class WrongType extends ConfigException {
public String path();
public ConfigValueType expected();
public ConfigValueType actual();
}Usage Examples:
try {
int port = config.getInt("server.port");
} catch (ConfigException.WrongType e) {
String path = e.path();
ConfigValueType expected = e.expected();
ConfigValueType actual = e.actual();
System.err.println(String.format(
"Type mismatch at %s: expected %s but got %s",
path, expected, actual
));
// Try alternative approaches
if (actual == ConfigValueType.STRING) {
try {
String portStr = config.getString(path);
int port = Integer.parseInt(portStr);
// Use parsed value
} catch (NumberFormatException nfe) {
// Handle invalid string format
}
}
}Thrown when configuration files contain syntax errors.
public static class Parse extends ConfigException {
public ConfigOrigin origin();
}Usage Examples:
try {
Config config = ConfigFactory.parseFile(configFile);
} catch (ConfigException.Parse e) {
ConfigOrigin origin = e.origin();
System.err.println(String.format(
"Parse error in %s at line %d: %s",
origin.filename(),
origin.lineNumber(),
e.getMessage()
));
// Handle parse error - maybe use defaults
Config defaultConfig = ConfigFactory.parseResources("reference.conf");
}Thrown for I/O related errors when loading configuration files.
public static class IO extends ConfigException {
public ConfigOrigin origin();
}Usage Examples:
try {
Config config = ConfigFactory.parseFile(new File("/etc/myapp/config.conf"));
} catch (ConfigException.IO e) {
System.err.println("I/O error reading configuration: " + e.getMessage());
// Try alternative locations
try {
config = ConfigFactory.parseFile(new File("./config.conf"));
} catch (ConfigException.IO e2) {
// Fall back to classpath resource
config = ConfigFactory.parseResources("application.conf");
}
}Thrown when substitutions cannot be resolved.
public static class UnresolvedSubstitution extends ConfigException {
public String path();
public String detail();
}Usage Examples:
try {
Config resolved = config.resolve();
} catch (ConfigException.UnresolvedSubstitution e) {
String path = e.path();
String detail = e.detail();
System.err.println(String.format(
"Cannot resolve substitution ${%s}: %s", path, detail
));
// Option 1: Allow partial resolution
Config partiallyResolved = config.resolve(
ConfigResolveOptions.defaults().setAllowUnresolved(true)
);
// Option 2: Provide missing values
Config withDefaults = config.withFallback(
ConfigFactory.parseString(path + " = \"default-value\"")
).resolve();
}Thrown when trying to access values from an unresolved configuration.
public static class NotResolved extends ConfigException {
// Standard exception methods
}Usage Examples:
Config config = ConfigFactory.parseString("value = ${missing.ref}");
try {
// This will fail because config is not resolved
String value = config.getString("value");
} catch (ConfigException.NotResolved e) {
System.err.println("Configuration must be resolved first: " + e.getMessage());
// Resolve first
try {
Config resolved = config.resolve();
String value = resolved.getString("value");
} catch (ConfigException.UnresolvedSubstitution ue) {
// Handle unresolved substitutions
}
}Thrown by the checkValid() method when validation fails.
public static class ValidationFailed extends ConfigException {
public Iterable<ValidationProblem> problems();
public static class ValidationProblem {
public String path();
public String problem();
public ConfigOrigin origin();
}
}Usage Examples:
Config reference = ConfigFactory.parseResources("reference.conf");
Config config = ConfigFactory.load();
try {
config.checkValid(reference);
} catch (ConfigException.ValidationFailed e) {
System.err.println("Configuration validation failed:");
for (ConfigException.ValidationProblem problem : e.problems()) {
String path = problem.path();
String description = problem.problem();
ConfigOrigin origin = problem.origin();
System.err.println(String.format(
" %s: %s (from %s:%d)",
path, description,
origin.filename(), origin.lineNumber()
));
}
// Handle validation failures
System.exit(1);
}Thrown when a configuration value is invalid for its intended use.
public static class BadValue extends ConfigException {
public String path();
public String detail();
}Usage Examples:
try {
Duration timeout = config.getDuration("timeout");
} catch (ConfigException.BadValue e) {
System.err.println(String.format(
"Invalid duration value at %s: %s",
e.path(), e.detail()
));
// Use default duration
Duration defaultTimeout = Duration.ofSeconds(30);
}
try {
ConfigMemorySize heapSize = config.getMemorySize("jvm.heap");
} catch (ConfigException.BadValue e) {
System.err.println(String.format(
"Invalid memory size at %s: %s",
e.path(), e.detail()
));
}Thrown when a path expression is malformed.
public static class BadPath extends ConfigException {
public String path();
public String detail();
}Usage Examples:
try {
// Invalid path with special characters
boolean value = config.getBoolean("invalid..path");
} catch (ConfigException.BadPath e) {
System.err.println(String.format(
"Invalid path expression '%s': %s",
e.path(), e.detail()
));
// Use quoted path or fix the path
String quotedPath = ConfigUtil.joinPath("invalid", "", "path");
boolean value = config.getBoolean(quotedPath);
}Thrown by ConfigBeanFactory when JavaBean creation fails.
public static class BadBean extends ConfigException {
// Standard exception methods
}Usage Examples:
public class DatabaseConfig {
private String host;
private int port;
// getters and setters...
}
try {
DatabaseConfig dbConfig = ConfigBeanFactory.create(
config.getConfig("database"),
DatabaseConfig.class
);
} catch (ConfigException.BadBean e) {
System.err.println("Failed to create DatabaseConfig bean: " + e.getMessage());
// Manual configuration extraction
DatabaseConfig dbConfig = new DatabaseConfig();
dbConfig.setHost(config.getString("database.host"));
dbConfig.setPort(config.getInt("database.port"));
}Thrown for internal library errors that indicate bugs.
public static class BugOrBroken extends ConfigException {
// Standard exception methods
}Usage: This exception indicates a bug in the Config library itself. If encountered, it should be reported to the library maintainers.
Generic exception for miscellaneous error conditions.
public static class Generic extends ConfigException {
// Standard exception methods
}Handle configuration errors while maintaining application functionality.
public class ConfigService {
private final Config config;
public ConfigService() {
Config primaryConfig = null;
try {
// Try primary configuration source
primaryConfig = ConfigFactory.load("application.conf");
} catch (ConfigException.IO e) {
System.err.println("Primary config not found, trying backup");
try {
primaryConfig = ConfigFactory.load("backup.conf");
} catch (ConfigException e2) {
System.err.println("Backup config failed, using defaults");
primaryConfig = ConfigFactory.parseResources("reference.conf");
}
}
this.config = primaryConfig;
}
public String getStringWithDefault(String path, String defaultValue) {
try {
return config.getString(path);
} catch (ConfigException.Missing | ConfigException.WrongType e) {
System.err.println("Using default for " + path + ": " + e.getMessage());
return defaultValue;
}
}
}Implement recovery strategies for different exception types.
public Config loadConfigWithRecovery(String resourceName) {
try {
return ConfigFactory.load(resourceName).resolve();
} catch (ConfigException.Parse e) {
// Parse error - try alternative formats
System.err.println("Parse error, trying JSON format: " + e.getMessage());
return ConfigFactory.parseResources(resourceName + ".json")
.resolve();
} catch (ConfigException.UnresolvedSubstitution e) {
// Resolution error - provide fallbacks
System.err.println("Resolution error, using partial config: " + e.getMessage());
return ConfigFactory.load(resourceName)
.resolve(ConfigResolveOptions.defaults().setAllowUnresolved(true));
} catch (ConfigException.IO e) {
// I/O error - use embedded defaults
System.err.println("I/O error, using embedded config: " + e.getMessage());
return ConfigFactory.parseResources("reference.conf").resolve();
}
}Comprehensive error reporting for configuration issues.
public void validateConfiguration(Config config) throws ConfigException {
List<String> errors = new ArrayList<>();
// Check required paths
String[] requiredPaths = {
"database.url", "database.username", "server.port"
};
for (String path : requiredPaths) {
try {
if (!config.hasPath(path)) {
errors.add("Missing required configuration: " + path);
} else if (config.getIsNull(path)) {
errors.add("Required configuration is null: " + path);
}
} catch (ConfigException e) {
errors.add("Error checking " + path + ": " + e.getMessage());
}
}
// Check value types and ranges
try {
int port = config.getInt("server.port");
if (port < 1 || port > 65535) {
errors.add("Server port must be between 1 and 65535, got: " + port);
}
} catch (ConfigException.Missing e) {
// Already handled above
} catch (ConfigException.WrongType e) {
errors.add("Server port must be a number: " + e.getMessage());
}
if (!errors.isEmpty()) {
String message = "Configuration validation failed:\n" +
String.join("\n", errors);
throw new ConfigException.Generic(message);
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-typesafe--config