alibaba/spring-ai-alibaba · error · BizException

BuildToolSchemaError

BuildToolSchemaError

Error message

Failed to build tool schema.

What it means

Thrown by createTool when OpenApiUtils.buildOpenAPIYaml fails to produce a usable OpenAPI schema for the new tool: the generated YAML is blank or the generated document does not parse into a valid OpenAPI object. The library refuses to persist a tool whose API schema cannot be built or parsed, because the tool would be unusable at invocation time.

Solutions

  1. Validate the Tool config fields (name, description, path, requestMethod, server host URL) are populated and well-formed before calling createTool.
  2. Remove request/parameter combos OpenAPI cannot express, e.g. body params on GET requests (see INVALID_PARAMS check).
  3. Call OpenApiUtils.buildOpenAPIYaml/parseOpenAPIObject locally to see exactly what is blank or failing to parse.
  4. Check server logs / exception cause chain for the underlying YAML generation or parsing exception.

Example fix

// before: createTool with incomplete config
Tool tool = new Tool();
tool.setName("weather"); // no path, no requestMethod, no servers
toolService.createTool(context, tool);

// after: fully populated config
ToolConfig config = new ToolConfig();
config.setPath("/v1/weather");
config.setRequestMethod("GET");
config.setServiceGroup("https://api.example.com");
Tool tool = new Tool();
tool.setName("weather");
tool.setConfig(config);
Defensive patterns

Strategy: validation

Validate before calling

// pre-check the schema before createTool
String yaml = OpenApiUtils.buildOpenAPIYaml(plugin, tool);
if (yaml == null || yaml.isBlank() || !OpenApiUtils.parseOpenAPIObject(yaml).isEmpty()) {
    throw new IllegalArgumentException("tool config cannot produce a valid OpenAPI schema");
}
toolService.createTool(context, tool);

Try / catch

try {
    toolService.createTool(context, tool);
} catch (BizException e) {
    if ("BuildToolSchemaError".equals(e.getCode())) {
        // show schema editor / config validation errors to the user
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling PluginServiceImpl.createTool with a Tool whose config (path, requestMethod, host/server URL, parameters) is incomplete or malformed so OpenApiUtils.buildOpenAPIYaml returns blank or OpenApiUtils.parseOpenAPIObject(yaml) returns a non-empty error list.

Common situations: Importing a plugin tool from a hand-written OpenAPI spec with a missing servers URL or invalid path; a request method/parameter combination that cannot be expressed in OpenAPI (e.g. GET with body params was not blocked upstream); YAML serialization producing empty output for edge-case configs.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at spring-ai-alibaba-admin/spring-ai-alibaba-admin-server-core/src/main/java/com/alibaba/cloud/ai/studio/core/base/service/impl/PluginServiceImpl.java:295

			}

			Tool.ToolConfig config = tool.getConfig();
			List<ApiParameter> inputParams = config.getInputParams();
			if (!CollectionUtils.isEmpty(inputParams)) {
				for (ApiParameter apiParameter : inputParams) {
					String location = apiParameter.getLocation();
					if ("Get".equals(config.getRequestMethod()) && location.equals("Body")) {
						throw new BizException(
								ErrorCode.INVALID_PARAMS.toError("input_params", "Get method not support body params"));
					}
				}
			}

			// convert to swagger yaml
			String yaml = OpenApiUtils.buildOpenAPIYaml(plugin, tool);

			if (StringUtils.isBlank(yaml) || !CollectionUtils.isEmpty(OpenApiUtils.parseOpenAPIObject(yaml))) {
				throw new BizException(ErrorCode.BUILD_TOOL_SCHEMA_ERROR.toError());
			}

			String toolId = IdGenerator.idStr();
			ToolEntity entity = BeanCopierUtils.copy(tool, ToolEntity.class);
			entity.setToolId(toolId);
			entity.setPluginId(tool.getPluginId());
			entity.setWorkspaceId(context.getWorkspaceId());
			entity.setConfig(JsonUtils.toJson(tool.getConfig()));
			entity.setApiSchema(yaml);
			entity.setStatus(ToolStatus.DRAFT);
			entity.setEnabled(false);
			entity.setTestStatus(ToolTestStatus.NOT_TEST);

			entity.setGmtCreate(new Date());
			entity.setGmtModified(new Date());
			entity.setCreator(context.getAccountId());
			entity.setModifier(context.getAccountId());

View on GitHub (pinned to f82da0b50f)