OtterMind/Chat2DB · error · BusinessException

routine.operation.typeUnsupported

routine.operation.typeUnsupported

Error message

routine.operation.typeUnsupported

What it means

Thrown by normalizeRoutineType when operation.getRoutineType(), after trim+uppercase, is neither FUNCTION nor PROCEDURE. This is a hard validation: only those two routine kinds are supported by the MySQL routine manager. Any other value (including null, empty, 'TRIGGER', 'EVENT') is rejected before any SQL is built.

Source

Thrown at chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlRoutineManager.java:328

                        .toList();
            }

            return metaData.getProcedureParameters(connection, databaseName, StringUtils.trimToNull(operation.getSchemaName()),
                            routineName)
                    .stream()
                    .map(mysqlRoutineConverter::procedureParameter2routineParameter)
                    .filter(Objects::nonNull)
                    .sorted((left, right) -> Integer.compare(left.ordinalPosition(), right.ordinalPosition()))
                    .toList();
        } catch (Exception e) {
            throw new BusinessException("routine.operation.parameterLoadFailed", new Object[]{e.getMessage()}, e);
        }
    }

    private String normalizeRoutineType(String routineType) {
        String normalized = StringUtils.trimToEmpty(routineType).toUpperCase(Locale.ROOT);
        if (!FUNCTION.equals(normalized) && !PROCEDURE.equals(normalized)) {
            throw new BusinessException("routine.operation.typeUnsupported");
        }
        return normalized;
    }

    private String requireRoutineName(RoutineOperation operation) {
        String routineName = StringUtils.trimToEmpty(operation.getRoutineName());
        if (StringUtils.isBlank(routineName)) {
            throw new BusinessException("routine.operation.nameRequired");
        }
        return routineName;
    }

    private String requireDatabaseName(RoutineOperation operation) {
        String databaseName = StringUtils.trimToEmpty(operation.getDatabaseName());
        if (StringUtils.isBlank(databaseName)) {
            throw new BusinessException("routine.operation.databaseRequired");
        }
        return databaseName;

View on GitHub (pinned to 5ee1e990e7)

Solutions

  1. Set operation.setRoutineType("FUNCTION") or "PROCEDURE" (case-insensitive) before calling.
  2. Validate the routineType at the request boundary and reject unsupported kinds with a clear message.
  3. If the value comes from metadata, map it to FUNCTION/PROCEDURE and skip other kinds.
  4. Confirm the RoutineOperation builder is not leaving routineType unset.

Example fix

// before
operation.setRoutineType(rawType);
routineManager.previewInvocation(connection, operation);

// after
String type = StringUtils.trimToEmpty(rawType).toUpperCase(Locale.ROOT);
if (!"FUNCTION".equals(type) && !"PROCEDURE".equals(type)) {
    throw new IllegalArgumentException("Unsupported routine type: " + rawType);
}
operation.setRoutineType(type);
routineManager.previewInvocation(connection, operation);
Defensive patterns

Strategy: validation

Validate before calling

String t = StringUtils.trimToEmpty(rawType).toUpperCase(Locale.ROOT);
if (!"FUNCTION".equals(t) && !"PROCEDURE".equals(t)) {
    throw new IllegalArgumentException("Unsupported routine type: " + rawType);
}
operation.setRoutineType(t);

Type guard

static boolean isSupportedRoutineType(String type) {
    String t = StringUtils.trimToEmpty(type).toUpperCase(Locale.ROOT);
    return "FUNCTION".equals(t) || "PROCEDURE".equals(t);
}

Prevention

When it happens

Trigger: Calling any routine-manager entry point (previewInvocation, previewMigration, executeMigration) with operation.getRoutineType() returning a value other than FUNCTION/PROCEDURE, case-insensitively.

Common situations: Frontend sends the routine type from a dropdown that includes unsupported kinds; a null/blank routineType field in the request payload; a copy of the operation object left with a default/null routineType; mislabeling an EVENT or TRIGGER as a routine.

Related errors


AI-assisted analysis of OtterMind/Chat2DB@5ee1e990e7 (2026-08-14). Data as JSON: /api/errors/928753bf30d59612. Report an issue: GitHub.