{"record":{"id":"83d27328ac26811a","repo":"alibaba/spring-ai-alibaba","slug":"unable-to-create-tables-83d273","errorCode":null,"errorMessage":"Unable to create tables","messagePattern":"Unable to create tables","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"critical","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/oracle/OracleSaver.java","lineNumber":579,"sourceCode":"\t */\n\tprotected void initTables() {\n\t\ttry (Connection connection = dataSource.getConnection();\n\t\t\t Statement statement = connection.createStatement()) {\n\t\t\tif (createOption == CreateOption.CREATE_OR_REPLACE) {\n\t\t\t\tstatement.addBatch(DROP_THREAD_INDEX);\n\t\t\t\tstatement.addBatch(DROP_CHECKPOINT_TABLE);\n\t\t\t\tstatement.addBatch(DROP_THREAD_TABLE);\n\t\t\t}\n\t\t\tif (createOption == CreateOption.CREATE_OR_REPLACE ||\n\t\t\t\t\tcreateOption == CreateOption.CREATE_IF_NOT_EXISTS) {\n\t\t\t\tstatement.addBatch(CREATE_THREAD_TABLE);\n\t\t\t\tstatement.addBatch(INDEX_THREAD_TABLE);\n\t\t\t\tstatement.addBatch(CREATE_CHECKPOINT_TABLE);\n\t\t\t\tstatement.executeBatch();\n\t\t\t}\n\t\t}\n\t\tcatch (SQLException sqlException) {\n\t\t\tthrow new RuntimeException(\"Unable to create tables\", sqlException);\n\t\t}\n\t}\n\n\t/**\n\t * A builder for OracleSaver.\n\t */\n\tpublic static class Builder {\n\t\tprivate DataSource dataSource;\n\t\tprivate CreateOption createOption = CreateOption.CREATE_IF_NOT_EXISTS;\n\t\tprivate StateSerializer stateSerializer;\n\t\tprivate int maxCachedThreads = 1024;\n\n\t\t/**\n\t\t * Sets the datasource\n\t\t *\n\t\t * @param dataSource the datasource\n\t\t * @return this builder\n\t\t */","sourceCodeStart":561,"sourceCodeEnd":597,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/oracle/OracleSaver.java#L561-L597","documentation":"OracleSaver.initTables wraps any SQLException raised while batch-executing the DDL statements that create the checkpoint tables and index into a RuntimeException('Unable to create tables'). This happens during saver initialization when Oracle rejects the CREATE TABLE / CREATE INDEX statements. It means the checkpoint persistence schema could not be set up, so the saver cannot be used.","triggerScenarios":"Calling OracleSaver builder initTables (or constructing a saver that auto-initializes) when the DB user lacks CREATE TABLE privilege, a table with the same name already exists with an incompatible definition, the connection points to an unreachable/invalid schema, or Oracle throws ORA- errors on the DDL batch (e.g. ORA-00955 name already used, ORA-01031 insufficient privileges).","commonSituations":"Deploying to an Oracle account with read/write but no DDL permissions; pointing at a shared schema where the checkpoint tables already exist; wrong JDBC URL or service name; network/credentials problems surfacing as SQL exceptions during DDL.","solutions":["Grant the connecting Oracle user CREATE TABLE privilege (GRANT CREATE TABLE TO user) or run initTables as a DBA-backed schema user.","Check the wrapped SQLException cause for the exact ORA- code; if ORA-00955 (name in use), the tables already exist and you can skip initTables.","Verify the JDBC URL, service name, and credentials; test connectivity with a simple SELECT 1 FROM DUAL before initializing.","If initialization is idempotency-related, pre-create the checkpoint tables/index manually with the exact names the saver expects."],"exampleFix":"// before\nOracleSaver.builder().dataSource(ds).stateSerializer(serializer).build(); // fails: no CREATE TABLE privilege\n// after\n// grant DDL rights or pre-create tables, then optionally skip auto-init:\n// GRANT CREATE TABLE TO app_user;\nOracleSaver.builder().dataSource(ds).stateSerializer(serializer).build();","handlingStrategy":"try-catch","validationCode":"// Java: pre-check privileges and existing tables before initTables\ntry (Connection c = dataSource.getConnection(); Statement s = c.createStatement()) {\n    s.execute(\"SELECT 1 FROM DUAL\"); // connectivity\n    ResultSet rs = c.getMetaData().getTables(null, null, \"CHECKPOINTS\", new String[]{\"TABLE\"});\n    if (rs.next()) { /* tables already exist: skip init */ }\n}","typeGuard":null,"tryCatchPattern":"try {\n    saverBuilder.build();\n} catch (RuntimeException e) {\n    if (\"Unable to create tables\".equals(e.getMessage()) && e.getCause() instanceof SQLException sql) {\n        // inspect sql.getErrorCode() for ORA-00955 / ORA-01031 and act accordingly\n    }\n}","preventionTips":["Grant CREATE TABLE to the app's DB user or pre-create the schema via migration scripts.","Run a connectivity smoke query (SELECT 1 FROM DUAL) before saver initialization.","Make table creation idempotent and managed by DB migrations instead of app startup.","Always log the wrapped SQLException cause and Oracle error code."],"tags":["oracle","database","ddl","checkpoint","initialization"],"backgroundTag":"database-write-failed","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}