spring-projects/spring-framework · error · IllegalArgumentException

Service locator exception [${exceptionClass.getName()}] neit

Error message

Service locator exception [${exceptionClass.getName()}] neither has a (String, Throwable) constructor nor a (String) constructor

What it means

Thrown by ServiceLocatorFactoryBean.determineServiceLocatorExceptionConstructor() when the custom exception class set via setServiceLocatorExceptionClass does not expose any of the supported constructors: (String, Throwable), (Throwable), or (String). ServiceLocatorFactoryBean needs to wrap lookup failures (NoSuchBeanDefinitionException etc.) into the user's exception type, and it can only do so reflectively if such a constructor exists. The error message lists the exception class name that failed the check.

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 69bf83ad71)

Solutions

  1. Add a public constructor to your exception class with one of: (String, Throwable), (Throwable), or (String). The (String, Throwable) form is preferred so both message and cause propagate.
  2. If you cannot change the exception class, wrap it in a custom subclass that adds such a constructor, or stop using setServiceLocatorExceptionClass and let Spring throw its own BeansException subclasses.
  3. Ensure the constructor is public so reflection (Class.getConstructor) can find it.

Example fix

// before (broken)
public class MyException extends RuntimeException {
  public MyException(int code) { ... }
}
fb.setServiceLocatorExceptionClass(MyException.class); // throws
// after
public class MyException extends RuntimeException {
  public MyException(String msg, Throwable cause) { super(msg, cause); }
  public MyException(String msg) { super(msg); }
}
Defensive patterns

Strategy: type-guard

Validate before calling

Class<? extends Exception> c = MyException.class;
boolean hasCtor =
    hasPublicCtor(c, String.class, Throwable.class) ||
    hasPublicCtor(c, Throwable.class) ||
    hasPublicCtor(c, String.class);
if (!hasCtor) {
    throw new IllegalStateException(c.getName() + " needs a (String,Throwable)/(Throwable)/(String) constructor");
}
fb.setServiceLocatorExceptionClass(c);

Type guard

static boolean hasSupportedLocatorExceptionCtor(Class<? extends Exception> c) {
    try { c.getConstructor(String.class, Throwable.class); return true; }
    catch (NoSuchMethodException ignore) {}
    try { c.getConstructor(Throwable.class); return true; }
    catch (NoSuchMethodException ignore) {}
    try { c.getConstructor(String.class); return true; }
    catch (NoSuchMethodException ignore) {}
    return false;
}

Try / catch

try {
    fb.setServiceLocatorExceptionClass(MyException.class);
} catch (IllegalArgumentException ex) {
    if (ex.getMessage().contains("neither has a")) {
        // add a (String, Throwable) constructor to MyException, then retry
    }
    throw ex;
}

Prevention

When it happens

Trigger: Calling setServiceLocatorExceptionClass(MyException.class) where MyException has only a no-arg or (int) constructor. Providing an exception class with private/package-private constructors that reflection cannot reach. Passing a checked exception whose constructors don't match the supported signatures.

Common situations: Custom business exception without the conventional message/cause constructors. Refactoring the exception class and removing the (String, Throwable) constructor. Using a library exception class whose API differs.

Related errors


AI-assisted analysis of spring-projects/spring-framework@69bf83ad71 (2026-08-09). Data as JSON: /api/errors/bc76ade6ff3baefa. Report an issue: GitHub.