{"record":{"id":"c73ac0c52df1cb6a","repo":"OtterMind/Chat2DB","slug":"routine-operation-namerequired","errorCode":"routine.operation.nameRequired","errorMessage":"routine.operation.nameRequired","messagePattern":"routine\\.operation\\.nameRequired","errorType":"validation","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlRoutineManager.java","lineNumber":336,"sourceCode":"                    .sorted((left, right) -> Integer.compare(left.ordinalPosition(), right.ordinalPosition()))\n                    .toList();\n        } catch (Exception e) {\n            throw new BusinessException(\"routine.operation.parameterLoadFailed\", new Object[]{e.getMessage()}, e);\n        }\n    }\n\n    private String normalizeRoutineType(String routineType) {\n        String normalized = StringUtils.trimToEmpty(routineType).toUpperCase(Locale.ROOT);\n        if (!FUNCTION.equals(normalized) && !PROCEDURE.equals(normalized)) {\n            throw new BusinessException(\"routine.operation.typeUnsupported\");\n        }\n        return normalized;\n    }\n\n    private String requireRoutineName(RoutineOperation operation) {\n        String routineName = StringUtils.trimToEmpty(operation.getRoutineName());\n        if (StringUtils.isBlank(routineName)) {\n            throw new BusinessException(\"routine.operation.nameRequired\");\n        }\n        return routineName;\n    }\n\n    private String requireDatabaseName(RoutineOperation operation) {\n        String databaseName = StringUtils.trimToEmpty(operation.getDatabaseName());\n        if (StringUtils.isBlank(databaseName)) {\n            throw new BusinessException(\"routine.operation.databaseRequired\");\n        }\n        return databaseName;\n    }\n\n    private String ensureSqlEndsWithSemicolon(String sql) {\n        String trimmed = StringUtils.trimToEmpty(sql);\n        if (StringUtils.isBlank(trimmed)) {\n            throw new BusinessException(\"routine.operation.ddlRequired\");\n        }\n        return trimmed.endsWith(\";\") ? trimmed : trimmed + \";\";","sourceCodeStart":318,"sourceCodeEnd":354,"githubUrl":"https://github.com/OtterMind/Chat2DB/blob/5ee1e990e73fbcae1969dc554be254fedb3ab888/chat2db-community-server/chat2db-community-plugins/chat2db-community-mysql/src/main/java/ai/chat2db/plugin/mysql/MysqlRoutineManager.java#L318-L354","documentation":"Thrown by requireRoutineName when operation.getRoutineName(), after trim, is blank. The routine name is mandatory for every routine operation (preview, migration, invocation) because it becomes the DROP/CREATE/CALL target. There is no default or fallback name.","triggerScenarios":"Any routine-manager method that calls requireRoutineName (buildMigrationPlan, previewInvocation path) with operation.getRoutineName() returning null, empty, or whitespace-only.","commonSituations":"The frontend submits a routine operation without selecting a routine; a list/tree node with no name is passed through; the request payload was built programmatically and the name field was omitted.","solutions":["Populate operation.setRoutineName(name) with a non-blank value before invoking the manager.","Validate at the controller/service boundary that routineName is non-blank and return a 400.","Guard the UI so a routine must be selected before the operation button is enabled.","Log the full operation to find which caller omitted the name."],"exampleFix":"// before\nroutineManager.previewInvocation(connection, operation);\n\n// after\nif (StringUtils.isBlank(operation.getRoutineName())) {\n    throw new IllegalArgumentException(\"routineName is required\");\n}\nroutineManager.previewInvocation(connection, operation);","handlingStrategy":"validation","validationCode":"if (StringUtils.isBlank(operation.getRoutineName())) {\n    throw new IllegalArgumentException(\"routineName is required\");\n}","typeGuard":"static boolean hasRoutineName(RoutineOperation op) {\n    return op != null && StringUtils.isNotBlank(op.getRoutineName());\n}","tryCatchPattern":null,"preventionTips":["Require a selected routine in the UI before enabling operations.","Validate routineName at the controller boundary and return 400.","Propagate the tree-node name into the operation object.","Log the operation to find which caller omitted the name."],"tags":["mysql","routine","validation"],"backgroundTag":null,"analyzedSha":"5ee1e990e73fbcae1969dc554be254fedb3ab888","analyzedAt":"2026-08-14T07:05:03.077Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}