spring-projects/spring-framework · error · IllegalArgumentException
Service locator exception [{}] neither has a (String, Throwa
Error message
Service locator exception [{}] neither has a (String, Throwable) constructor nor a (String) constructor What it means
Thrown by ServiceLocatorFactoryBean.determineServiceLocatorExceptionConstructor() when the class passed to setServiceLocatorExceptionClass() lacks all three required constructors. ServiceLocatorFactoryBean lets you translate internal Spring BeansException failures into a custom application exception; to do that it must be able to construct your exception from either a (String, Throwable) pair, a single (Throwable), or a single (String). If none of those public constructors exists, it cannot wrap the lookup cause and rejects the exception class at configuration time (the setter is called during bean initialization, so the error surfaces as the context fails to start).
Source
Thrown at spring-beans/src/main/java/org/springframework/beans/factory/config/ServiceLocatorFactoryBean.java:294
* @param exceptionClass the exception class
* @return the constructor to use
* @see #setServiceLocatorExceptionClass
*/
@SuppressWarnings("unchecked")
protected Constructor<Exception> determineServiceLocatorExceptionConstructor(Class<? extends Exception> exceptionClass) {
try {
return (Constructor<Exception>) exceptionClass.getConstructor(String.class, Throwable.class);
}
catch (NoSuchMethodException ex) {
try {
return (Constructor<Exception>) exceptionClass.getConstructor(Throwable.class);
}
catch (NoSuchMethodException ex2) {
try {
return (Constructor<Exception>) exceptionClass.getConstructor(String.class);
}
catch (NoSuchMethodException ex3) {
throw new IllegalArgumentException(
"Service locator exception [" + exceptionClass.getName() +
"] neither has a (String, Throwable) constructor nor a (String) constructor");
}
}
}
}
/**
* Create a service locator exception for the given cause.
* Only called in case of a custom service locator exception.
* <p>The default implementation can handle all variations of
* message and exception arguments.
* @param exceptionConstructor the constructor to use
* @param cause the cause of the service lookup failure
* @return the service locator exception to throw
* @see #setServiceLocatorExceptionClass
*/
protected Exception createServiceLocatorException(Constructor<Exception> exceptionConstructor, BeansException cause) {View on GitHub (pinned to e8729d0438)
Solutions
- Add a public constructor to your custom exception class with one of these signatures: (String, Throwable), (Throwable), or (String). The (String, Throwable) form is preferred so both the message and the original cause are preserved.
- If you cannot modify the exception class, switch to a different exception class that already has one of the required constructors, or omit setServiceLocatorExceptionClass entirely and let Spring throw its unchecked NoSuchBeanDefinitionException.
- Verify the constructor is public — getConstructor() only returns public members; package-private or private constructors will not be found even with the right parameter types.
- Rebuild/redeploy after editing the exception class so the reflective lookup sees the new constructor.
Example fix
// before
public class ServiceException extends Exception {
public ServiceException(int code) { ... }
public ServiceException(String msg, int code) { ... }
}
// after
public class ServiceException extends Exception {
public ServiceException(int code) { ... }
public ServiceException(String msg, int code) { ... }
public ServiceException(String message, Throwable cause) {
super(message, cause);
}
public ServiceException(Throwable cause) {
super(cause);
}
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the custom exception class BEFORE wiring it into the FactoryBean.
private static void assertValidLocatorException(Class<? extends Exception> exClass) {
boolean ok = hasPublicCtor(exClass, String.class, Throwable.class)
|| hasPublicCtor(exClass, Throwable.class)
|| hasPublicCtor(exClass, String.class);
if (!ok) {
throw new IllegalArgumentException(exClass.getName() +
" must declare a public (String, Throwable), (Throwable), or (String) constructor");
}
}
private static boolean hasPublicCtor(Class<?> c, Class<?>... params) {
try { c.getConstructor(params); return true; }
catch (NoSuchMethodException e) { return false; }
} Type guard
// Reflective structural guard you can unit-test against the exception class.
static boolean isAcceptableLocatorException(Class<? extends Exception> c) {
try { c.getConstructor(String.class, Throwable.class); return true; }
catch (NoSuchMethodException ignored) {}
try { c.getConstructor(Throwable.class); return true; }
catch (NoSuchMethodException ignored) {}
try { c.getConstructor(String.class); return true; }
catch (NoSuchMethodException ignored) {}
return false;
} Try / catch
// setServiceLocatorExceptionClass is invoked during bean init; catch IllegalArgumentException
// to rethrow as a contextual BeanCreationException, not to silently substitute another class.
try {
fb.setServiceLocatorExceptionClass(MyException.class);
} catch (IllegalArgumentException ex) {
throw new BeanCreationException(
"Cannot use MyException as service-locator exception: " + ex.getMessage(), ex);
} Prevention
- Design application exception classes that wrap other throwables with a standard (String message, Throwable cause) constructor from the start — this satisfies Spring and most other frameworks.
- Keep a single shared base exception in your domain with the (String, Throwable) and (Throwable) constructors; subclass it for specific cases instead of authoring independent hierarchies.
- Write a one-off unit test that calls new ServiceLocatorFactoryBean().setServiceLocatorExceptionClass(MyException.class) against every locator exception class in the codebase.
- Prefer omitting setServiceLocatorExceptionClass entirely unless callers genuinely need a checked/domain exception; the default unchecked NoSuchBeanDefinitionException is often acceptable.
- When refactoring an exception's constructors, grep for setServiceLocatorExceptionClass and the class name to catch downstream Spring config that depends on the old shape.
When it happens
Trigger: Calling setServiceLocatorExceptionClass(MyAppException.class) (XML <property name="serviceLocatorExceptionClass" value="..."/>) where MyAppException only exposes constructors like (int code), (String message, int code), or only a no-arg/default constructor. Also triggered when the exception class is an enum-implementing pseudo-exception, a checked exception with private/package-private constructors, or when the intended (String, Throwable) constructor was renamed/removed during a refactor of the application exception hierarchy.
Common situations: Adopting ServiceLocatorFactoryBean and pointing serviceLocatorExceptionClass at a pre-existing domain exception that was designed for business errors (message+code) rather than wrapping; an upgrade that switches the custom exception from a single-String ctor to a (String, ErrorCode) ctor; team shares a common exception that no longer has a Throwable constructor; refactoring error hierarchies without realizing Spring needs one of the three shapes.
Related errors
- Property 'serviceLocatorInterface' is required
- Unable to locate method [{}] on bean [{}]
- AOP configuration seems to be invalid: tried calling method
- Illegal arguments for constructor
- Could not copy property '${targetPd.getName()}' from source
AI-assisted analysis of spring-projects/spring-framework@e8729d0438 (2026-08-04).
Data as JSON: /data/errors/1c408ff1af426d30.json.
Report an issue: GitHub.