ssssssss-team/spider-flow · error · RuntimeException

Couldn't call method '" + javaMethod.getName() + "' with…

Error message

Couldn't call method '" + javaMethod.getName() + "' with arguments '" + Arrays.toString(arguments) + "' on object of type '" + obj.getClass().getSimpleName() + "'.

What it means

JavaReflection.callMethod invokes a reflective Method with the given arguments via Method.invoke. Any failure (IllegalAccessException, IllegalArgumentException, InvocationTargetException from the method body itself) is rethrown as a RuntimeException describing the method, its arguments, and the target object's class, with the original throwable as cause.

Solutions

  1. Inspect getCause() of the RuntimeException: InvocationTargetException means the target method itself threw — fix the method logic or its inputs
  2. Verify argument count and types exactly match the Method signature (boxed primitives count)
  3. Ensure the method is accessible (public, or setAccessible(true))
  4. Check the target object is not null and is an instance of the declaring class

Example fix

// before
Object r = reflection.callMethod(obj, method, args);
// after
try {
    Object r = reflection.callMethod(obj, method, args);
} catch (RuntimeException e) {
    Throwable cause = e.getCause();
    if (cause instanceof InvocationTargetException && cause.getCause() != null) {
        throw (RuntimeException) cause.getCause(); // real business error
    }
    throw e;
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (obj == null || !((Method) method).getDeclaringClass().isInstance(obj)) {
    throw new IllegalArgumentException("Target object incompatible with method");
}
if (((Method) method).getParameterCount() != arguments.length) {
    throw new IllegalArgumentException("Argument count mismatch for method " + method);
}

Try / catch

try {
    return reflection.callMethod(obj, method, arguments);
} catch (RuntimeException e) {
    Throwable root = e.getCause();
    if (root instanceof InvocationTargetException && root.getCause() != null) {
        throw new ExpressionEvaluationException("Method threw: " + root.getCause().getMessage(), root.getCause());
    }
    throw new ExpressionEvaluationException("Cannot invoke method: " + e.getMessage(), e);
}

Prevention

When it happens

Trigger: Calling callMethod(obj, method, args...) during expression evaluation when the target method throws, the arguments don't match the signature, or the method is inaccessible.

Common situations: Invoking user-configured methods in spider expressions with wrong argument types/counts; invoking a method that itself throws a business exception; reflective access blocked by module rules.

Related errors


AI-assisted analysis of ssssssss-team/spider-flow@c799cca99c (2026-09-08). Data as JSON: /api/errors/c865c0d04afdb517. Report an issue: GitHub.

Appendix: source

Thrown at spider-flow-core/src/main/java/org/spiderflow/core/expression/interpreter/JavaReflection.java:326

		if (from == Long.class || from == long.class) {
			return to == float.class || to == Float.class || to == double.class || to == Double.class;
		}
		
		if(from == int[].class || from == Integer[].class){
			return to == Object[].class || to == float[].class || to == Float[].class || to == double[].class || to == Double[].class || to == long[].class || to == Long[].class;
		}
		
		return false;
	}

	@Override
	public Object callMethod (Object obj, Object method, Object... arguments) {
		Method javaMethod = (Method)method;
		try {
			return javaMethod.invoke(obj, arguments);
		} catch (Throwable t) {
			throw new RuntimeException("Couldn't call method '" + javaMethod.getName() + "' with arguments '" + Arrays.toString(arguments)
				+ "' on object of type '" + obj.getClass().getSimpleName() + "'.", t);
		}
	}

	private static class MethodSignature {
		private final String name;
		@SuppressWarnings("rawtypes") private final Class[] parameters;
		private final int hashCode;

		@SuppressWarnings("rawtypes")
		public MethodSignature (String name, Class[] parameters) {
			this.name = name;
			this.parameters = parameters;
			final int prime = 31;
			int hash = 1;
			hash = prime * hash + ((name == null) ? 0 : name.hashCode());
			hash = prime * hash + Arrays.hashCode(parameters);
			hashCode = hash;

View on GitHub (pinned to c799cca99c)