NOT NULL violation on test_case_steps when adding a test step — premature Hibernate flush triggered by JooqSessionGuard
Publié : jeu. août 27, 2026 10:27 am
version affectée : Squash TM 14.0.3 / 14.0.4 (Docker image squashtest/squash) Composant : tm.service — org.squashtest.tm.service.internal.repository.hibernate.MilestoneDaoImpl
Etapes pour reproduire l'erreur :
On a Squash TM 14.0.3/14.0.4 instance (milestones feature not even required to be in use — reproduces with 0 milestones in the database).
Open any test case with at least zero existing steps.
Add a new action step / prerequisite and save.
Observe "Une erreur imprévue est survenue" in the UI; server logs show the stack trace above.
Comportement observé :
Adding a new test step (action step / prerequisite) to a test case systematically fails with a NOT NULL constraint violation on test_case_steps.test_case_id, even on an instance with zero milestones defined. Reproduces on a test case with no pre-existing steps (empty list), ruling out any data corruption or step-ordering issue.
Stack trace (root cause) : Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "test_case_id" of relation "test_case_steps" violates not-null constraint Detail: Failing row contains (null, 39151, null). [insert into public.TEST_CASE_STEPS (STEP_ID) values (?)]
Call chain (from the full stack trace) : CheckBlockingMilestoneAspect.checkBlockingMilestone -> MilestoneDaoImpl.isTestStepBoundToBlockingMilestone(long) -> org.jooq.impl.DefaultDSLContext.fetchCount(...) -> JooqSessionGuard.executeStart(ExecuteContext) -> Hibernate Session.flush() (forced, session was dirty) -> premature INSERT of the incomplete test_case_steps row -> PSQLException: NOT NULL violation
Root cause : JooqSessionGuard (tm.service, @Since SquashTM 2.0) intentionally forces a Hibernate session flush before every jOOQ query execution, to avoid stale reads when the session is dirty. This is legitimate and documented behavior. However, MilestoneDaoImpl.isTestStepBoundToBlockingMilestone is the only one of the ~15 sibling "isXxxBoundToBlockingMilestone" methods in MilestoneDaoImpl that is implemented via jOOQ (dsl.fetchCount(...)); all the other ones (isRequirementBoundToBlockingMilestone, isCampaignBoundToBlockingMilestone, isExecutionStepBoundToBlockingMilestone, etc.) use plain JPA/HQL named queries and do not trigger JooqSessionGuard.
Nous utilisons une Azure database PostgreSQL flexible server en version 15.18.
Etapes pour reproduire l'erreur :
On a Squash TM 14.0.3/14.0.4 instance (milestones feature not even required to be in use — reproduces with 0 milestones in the database).
Open any test case with at least zero existing steps.
Add a new action step / prerequisite and save.
Observe "Une erreur imprévue est survenue" in the UI; server logs show the stack trace above.
Comportement observé :
Adding a new test step (action step / prerequisite) to a test case systematically fails with a NOT NULL constraint violation on test_case_steps.test_case_id, even on an instance with zero milestones defined. Reproduces on a test case with no pre-existing steps (empty list), ruling out any data corruption or step-ordering issue.
Stack trace (root cause) : Caused by: org.postgresql.util.PSQLException: ERROR: null value in column "test_case_id" of relation "test_case_steps" violates not-null constraint Detail: Failing row contains (null, 39151, null). [insert into public.TEST_CASE_STEPS (STEP_ID) values (?)]
Call chain (from the full stack trace) : CheckBlockingMilestoneAspect.checkBlockingMilestone -> MilestoneDaoImpl.isTestStepBoundToBlockingMilestone(long) -> org.jooq.impl.DefaultDSLContext.fetchCount(...) -> JooqSessionGuard.executeStart(ExecuteContext) -> Hibernate Session.flush() (forced, session was dirty) -> premature INSERT of the incomplete test_case_steps row -> PSQLException: NOT NULL violation
Root cause : JooqSessionGuard (tm.service, @Since SquashTM 2.0) intentionally forces a Hibernate session flush before every jOOQ query execution, to avoid stale reads when the session is dirty. This is legitimate and documented behavior. However, MilestoneDaoImpl.isTestStepBoundToBlockingMilestone is the only one of the ~15 sibling "isXxxBoundToBlockingMilestone" methods in MilestoneDaoImpl that is implemented via jOOQ (dsl.fetchCount(...)); all the other ones (isRequirementBoundToBlockingMilestone, isCampaignBoundToBlockingMilestone, isExecutionStepBoundToBlockingMilestone, etc.) use plain JPA/HQL named queries and do not trigger JooqSessionGuard.
Nous utilisons une Azure database PostgreSQL flexible server en version 15.18.