alibaba/spring-ai-alibaba · error · IllegalArgumentException

SkillRegistry cannot be null

Error message

SkillRegistry cannot be null

What it means

DisableSkillTool's constructor rejects a null SkillRegistry with an IllegalArgumentException. The registry is the sole dependency this tool needs to look up and disable skills, so constructing it without one is guaranteed to fail later; the library fails fast instead.

Source

Thrown at spring-ai-alibaba-agent-framework/src/main/java/com/alibaba/cloud/ai/graph/agent/hook/skills/DisableSkillTool.java:51

 */
public class DisableSkillTool implements BiFunction<DisableSkillTool.DisableSkillRequest, ToolContext, String> {

	public static final String DISABLE_SKILL = "disable_skill";

	public static final String DESCRIPTION = """
			Disables a skill in the current SkillRegistry instance without deleting any files.
			
			Usage:
			- Provide either skill_name or skill_path
			- If both are provided, they must refer to the same skill
			- Disabled skills are hidden from the current registry's listings and reads
			""";

	private final SkillRegistry skillRegistry;

	public DisableSkillTool(SkillRegistry skillRegistry) {
		if (skillRegistry == null) {
			throw new IllegalArgumentException("SkillRegistry cannot be null");
		}
		this.skillRegistry = skillRegistry;
	}

	public static ToolCallback createDisableSkillToolCallback(SkillRegistry skillRegistry, String description) {
		return FunctionToolCallback.builder(DISABLE_SKILL, new DisableSkillTool(skillRegistry))
				.description(description != null ? description : DESCRIPTION)
				.inputType(DisableSkillRequest.class)
				.build();
	}

	@Override
	public String apply(DisableSkillRequest request, ToolContext toolContext) {
		String skillName = normalize(request != null ? request.skillName : null);
		String skillPath = normalize(request != null ? request.skillPath : null);
		if (skillName == null && skillPath == null) {
			return "Error: Either skill_name or skill_path is required";
		}

View on GitHub (pinned to f82da0b50f)

Solutions

  1. Create a SkillRegistry before building the tool, e.g. SkillRegistry registry = FileSystemSkillRegistry.builder().build();
  2. If skills are optional, guard the registration: only add the disable-skill tool callback when a non-null registry is available.
  3. Check the factory/wiring path (createDisableSkillToolCallback) and ensure it is never invoked with a null registry.

Example fix

// before
ToolCallback cb = DisableSkillTool.createDisableSkillToolCallback(null, "Disable a skill");
// after
SkillRegistry registry = FileSystemSkillRegistry.builder().skillDirectory(skillsDir).build();
ToolCallback cb = DisableSkillTool.createDisableSkillToolCallback(registry, "Disable a skill");
Defensive patterns

Strategy: validation

Validate before calling

if (registry == null) { throw new IllegalStateException("Initialize SkillRegistry before creating DisableSkillTool"); }
DisableSkillTool tool = new DisableSkillTool(registry);

Type guard

boolean hasRegistry(SkillRegistry r) { return r != null; }

Try / catch

try { tool = new DisableSkillTool(registry); } catch (IllegalArgumentException e) { log.error("Registry missing: {}", e.getMessage()); }

Prevention

When it happens

Trigger: Calling new DisableSkillTool(null), or calling the static factory createDisableSkillToolCallback(skillRegistry, description) with a null first argument.

Common situations: Wiring skills into an agent where the FileSystemSkillRegistry was built conditionally (e.g. skills directory missing so the builder was skipped) and null was passed through; refactoring that removed registry initialization; Spring bean injection returning null due to a missing configuration.

Related errors


AI-assisted analysis of alibaba/spring-ai-alibaba@f82da0b50f (2026-09-09). Data as JSON: /api/errors/93789967b5e50d7b. Report an issue: GitHub.