{"record":{"id":"6d82560989c7f78a","repo":"hibernate/hibernate-orm","slug":"could-not-create-jdbc-nclob","errorCode":null,"errorMessage":"Could not create JDBC NClob","messagePattern":"Could not create JDBC NClob","errorType":"exception","errorClass":"JDBCException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/BlobAndClobCreator.java","lineNumber":224,"sourceCode":"\t * Obtain an {@link NClob} instance which can be written to a JDBC\n\t * {@link java.sql.PreparedStatement} using\n\t * {@link java.sql.PreparedStatement#setNClob(int, NClob)}.\n\t */\n\t@Override\n\tpublic NClob toJdbcNClob(NClob clob) {\n\t\ttry {\n\t\t\tif ( useConnectionToCreateLob ) {\n//\t\t\t\tfinal NClob jdbcClob = createNClob();\n//\t\t\t\tclob.getCharacterStream().transferTo( jdbcClob.setCharacterStream(1) );\n//\t\t\t\treturn jdbcClob;\n\t\t\t\treturn createNClob( clob.getSubString( 1, (int) clob.length() ) );\n\t\t\t}\n\t\t\telse {\n\t\t\t\treturn super.toJdbcNClob( clob );\n\t\t\t}\n\t\t}\n\t\tcatch (SQLException e) {\n\t\t\tthrow new JDBCException( \"Could not create JDBC NClob\", e );\n\t\t}\n//\t\tcatch (IOException e) {\n//\t\t\tthrow new HibernateException( \"Could not create JDBC NClob\", e );\n//\t\t}\n\t}\n}\n","sourceCodeStart":206,"sourceCodeEnd":231,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/BlobAndClobCreator.java#L206-L231","documentation":"Thrown by BlobAndClobCreator.toJdbcNClob when Hibernate converts an existing java.sql.NClob into a JDBC NClob. With connection-based LOB creation enabled, Hibernate calls clob.getSubString(1, (int) clob.length()) and Connection.createNClob(String); any SQLException is rethrown as a JDBCException with this message.","triggerScenarios":"Binding a nationalized character value as java.sql.NClob when the source NClob locator is already freed (owning connection committed/closed), when the driver's createNClob fails, or when the content exceeds Integer.MAX_VALUE characters.","commonSituations":"Using @Nationalized properties or NCHAR/NVARCHAR2 columns with drivers that invalidate NClob locators after transaction commit; reusing NClobs read in a previous request; missing national character set support in the DB or driver.","solutions":["Materialize the value as a String (or lobHelper.createNClob(String)) while the source connection is open and bind that instead","Map the attribute as a nationalized String (@Nationalized String) and let Hibernate handle wrapping","Check the underlying SQLException for the driver error; grant required LOB privileges and verify national charset setup","Upgrade the JDBC driver / database client library"],"exampleFix":"// before\nentity.setNdoc(nclobFromClosedConnection);\n\n// after\nString text = nclob.getSubString(1, (int) nclob.length());\nentity.setNdoc(session.getLobHelper().createNClob(text));","handlingStrategy":"try-catch","validationCode":"// verify NClob is usable before binding (locator still valid)\ntry {\n    if (nclob.length() >= 0) { /* locator alive */ }\n}\ncatch (SQLException e) {\n    // materialize from a fresh read or fail fast\n}","typeGuard":null,"tryCatchPattern":"try {\n    session.persist(entity);\n    session.flush();\n}\ncatch (JDBCException e) {\n    // e.getSQLException() carries the driver error for createNClob/getSubString\n    log.warn(\"NCLOB conversion failed: {}\", e.getSQLException(), e);\n}","preventionTips":["Use @Nationalized String mappings instead of hand-made NClobs","Materialize nationalized text while the source connection is open","Test Connection.createNClob() on your target driver during CI"],"tags":["jdbc","nclob","lob","nationalized","hibernate"],"backgroundTag":"jdbc-lob-creation-failed","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}