alibaba/spring-ai-alibaba · error · IllegalArgumentException

Either skill_name or skill_path is required

Error message

Either skill_name or skill_path is required

What it means

readSkillContent requires at least one identifier for the skill: either skill_name or skill_path in the request. If both are absent (or blank after normalization) it throws this IllegalArgumentException instead of attempting an ambiguous lookup.

Solutions

  1. Include either "skill_name" (registered name) or "skill_path" (file path) in the tool-call arguments.
  2. Validate the request object before calling apply/readSkillContent and return a corrective message to the model.
  3. Improve the tool description so the model reliably passes one of the two identifiers.

Example fix

// before
String content = tool.apply("{}"); // neither field set -> throws
// after
String content = tool.apply("{\"skill_name\": \"pdf-reader\"}");
Defensive patterns

Strategy: validation

Validate before calling

com.fasterxml.jackson.databind.JsonNode args = mapper.readTree(toolInput);
if (!args.hasNonNull("skill_name") && !args.hasNonNull("skill_path")) {
    return "Error: provide either skill_name or skill_path";
}

Type guard

boolean hasIdentifier(ReadSkillRequest r) { return r != null && (r.skillName != null || r.skillPath != null); }

Try / catch

try { return tool.apply(input); } catch (IllegalArgumentException e) { return "Bad arguments: " + e.getMessage(); }

Prevention

When it happens

Trigger: An LLM invokes the read_skill tool with an empty or missing arguments object, or supplies unrelated keys so both skillName and skillPath normalize to null.

Common situations: Model hallucinating tool arguments or omitting them entirely; a caller constructing ReadSkillRequest with neither field set; JSON deserialization dropping fields with different names than expected.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

		catch (IllegalStateException e) {
			logger.warn("Skill not found: {}", e.getMessage());
			return "Error: " + e.getMessage();
		}
		catch (IOException e) {
			logger.error("Error reading skill content: {}", e.getMessage(), e);
			return "Error reading skill file: " + e.getMessage();
		}
		catch (Exception e) {
			logger.error("Unexpected error reading skill: {}", e.getMessage(), e);
			return "Error: " + e.getMessage();
		}
	}

	private String readSkillContent(ReadSkillRequest request) throws IOException {
		String skillName = normalize(request != null ? request.skillName : null);
		String skillPath = normalize(request != null ? request.skillPath : null);
		if (skillName == null && skillPath == null) {
			throw new IllegalArgumentException("Either skill_name or skill_path is required");
		}

		if (skillName != null && skillPath != null) {
			SkillMetadata skillByName = skillRegistry.get(skillName)
					.orElseThrow(() -> new IllegalStateException("Skill not found: " + skillName));
			SkillMetadata skillByPath = skillRegistry.getByPath(skillPath)
					.orElseThrow(() -> new IllegalStateException("Skill not found: " + skillPath));
			if (!skillByName.getName().equals(skillByPath.getName())) {
				throw new IllegalArgumentException("skill_name and skill_path must refer to the same skill");
			}
			return skillRegistry.readSkillContent(skillByName.getName());
		}

		if (skillName != null) {
			return skillRegistry.readSkillContent(skillName);
		}
		return skillRegistry.readSkillContentByPath(skillPath);
	}

View on GitHub (pinned to f82da0b50f)