dependency-track icon indicating copy to clipboard operation
dependency-track copied to clipboard

Insert Statement conflicts with foreign key constraint

Open LearningEntity opened this issue 1 month ago • 4 comments

Current Behavior

We are getting los of foreign key constraint conflicts and deadlocks when upgrading to 4.13.5. We have deployed dependency-track via docker and are using MS SQL as database. Every Time when the ProjectMetricsUpdateTask is run, the Dependency Track API logs the following:

2025-11-03 10:15:45,968 ERROR [ProjectMetricsUpdateTask] An unexpected error occurred while updating metrics of component 97486344-94b1-47bd-8f88-2ce15dbeec9d javax.jdo.JDODataStoreException: Insert of object "org.dependencytrack.model.DependencyMetrics@64ff17bb" using statement "INSERT INTO DEPENDENCYMETRICS (COMPONENT_ID,CRITICAL,FINDINGS_AUDITED,FINDINGS_TOTAL,FINDINGS_UNAUDITED,FIRST_OCCURRENCE,HIGH,RISKSCORE,LAST_OCCURRENCE,LOW,MEDIUM,POLICYVIOLATIONS_AUDITED,POLICYVIOLATIONS_FAIL,POLICYVIOLATIONS_INFO,POLICYVIOLATIONS_LICENSE_AUDITED,POLICYVIOLATIONS_LICENSE_TOTAL,POLICYVIOLATIONS_LICENSE_UNAUDITED,POLICYVIOLATIONS_OPERATIONAL_AUDITED,POLICYVIOLATIONS_OPERATIONAL_TOTAL,POLICYVIOLATIONS_OPERATIONAL_UNAUDITED,POLICYVIOLATIONS_SECURITY_AUDITED,POLICYVIOLATIONS_SECURITY_TOTAL,POLICYVIOLATIONS_SECURITY_UNAUDITED,POLICYVIOLATIONS_TOTAL,POLICYVIOLATIONS_UNAUDITED,POLICYVIOLATIONS_WARN,PROJECT_ID,SUPPRESSED,UNASSIGNED_SEVERITY,VULNERABILITIES) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" failed : The INSERT statement conflicted with the FOREIGN KEY constraint "DEPENDENCYMETRICS_FK1". The conflict occurred in database "dtrack_prod", table "dbo.COMPONENT", column 'ID'. at org.datanucleus.api.jdo.JDOAdapter.getJDOExceptionForNucleusException(JDOAdapter.java:608) at org.datanucleus.api.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:702) at org.datanucleus.api.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:722) at org.dependencytrack.tasks.metrics.ComponentMetricsUpdateTask.lambda$updateMetrics$2(ComponentMetricsUpdateTask.java:163) at alpine.persistence.AbstractAlpineQueryManager.lambda$runInTransaction$6(AbstractAlpineQueryManager.java:564) at alpine.persistence.Transaction.call(Transaction.java:139) at alpine.persistence.AbstractAlpineQueryManager.callInTransaction(AbstractAlpineQueryManager.java:542) at alpine.persistence.AbstractAlpineQueryManager.runInTransaction(AbstractAlpineQueryManager.java:563) at alpine.persistence.AbstractAlpineQueryManager.runInTransaction(AbstractAlpineQueryManager.java:575) at org.dependencytrack.tasks.metrics.ComponentMetricsUpdateTask.updateMetrics(ComponentMetricsUpdateTask.java:155) at org.dependencytrack.tasks.metrics.ProjectMetricsUpdateTask.updateRegularProjectMetrics(ProjectMetricsUpdateTask.java:130) at org.dependencytrack.tasks.metrics.ProjectMetricsUpdateTask.updateMetrics(ProjectMetricsUpdateTask.java:79) at org.dependencytrack.tasks.metrics.ProjectMetricsUpdateTask.inform(ProjectMetricsUpdateTask.java:58) at alpine.event.framework.BaseEventService.lambda$publish$0(BaseEventService.java:110) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.base/java.lang.Thread.run(Unknown Source) Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The INSERT statement conflicted with the FOREIGN KEY constraint "DEPENDENCYMETRICS_FK1". The conflict occurred in database "dtrack_prod", table "dbo.COMPONENT", column 'ID'. at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:276) at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1787) at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:688) at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:607) at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7745) at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:4700) at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:321) at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:253) at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(SQLServerPreparedStatement.java:549) at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) at org.datanucleus.store.rdbms.SQLController.doExecuteStatementUpdate(SQLController.java:465) at org.datanucleus.store.rdbms.SQLController.executeStatementUpdateDeferRowCountCheckForBatching(SQLController.java:415) at org.datanucleus.store.rdbms.request.InsertRequest.execute(InsertRequest.java:532) at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.insertObjectInTable(RDBMSPersistenceHandler.java:235) at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.insertObject(RDBMSPersistenceHandler.java:211) at org.datanucleus.state.StateManagerImpl.internalMakePersistent(StateManagerImpl.java:4610) at org.datanucleus.state.StateManagerImpl.makePersistent(StateManagerImpl.java:4587) at org.datanucleus.ExecutionContextImpl.persistObjectInternal(ExecutionContextImpl.java:2077) at org.datanucleus.ExecutionContext.persistObjectInternal(ExecutionContext.java:320) at org.datanucleus.ExecutionContextImpl.persistObjectWork(ExecutionContextImpl.java:1925) at org.datanucleus.ExecutionContextImpl.persistObject(ExecutionContextImpl.java:1786) at org.datanucleus.api.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:697) ... 15 common frames omitted

Adding to this we are getting the following deadlock errors at the same time:

2025-11-03 10:15:45,865 ERROR [ProjectMetricsUpdateTask] An unexpected error occurred while updating metrics of component 8a9a00fe-cac6-4910-a1af-9cffd32881d0 javax.jdo.JDODataStoreException: Insert of object "org.dependencytrack.model.DependencyMetrics@6b0b6523" using statement "INSERT INTO DEPENDENCYMETRICS (COMPONENT_ID,CRITICAL,FINDINGS_AUDITED,FINDINGS_TOTAL,FINDINGS_UNAUDITED,FIRST_OCCURRENCE,HIGH,RISKSCORE,LAST_OCCURRENCE,LOW,MEDIUM,POLICYVIOLATIONS_AUDITED,POLICYVIOLATIONS_FAIL,POLICYVIOLATIONS_INFO,POLICYVIOLATIONS_LICENSE_AUDITED,POLICYVIOLATIONS_LICENSE_TOTAL,POLICYVIOLATIONS_LICENSE_UNAUDITED,POLICYVIOLATIONS_OPERATIONAL_AUDITED,POLICYVIOLATIONS_OPERATIONAL_TOTAL,POLICYVIOLATIONS_OPERATIONAL_UNAUDITED,POLICYVIOLATIONS_SECURITY_AUDITED,POLICYVIOLATIONS_SECURITY_TOTAL,POLICYVIOLATIONS_SECURITY_UNAUDITED,POLICYVIOLATIONS_TOTAL,POLICYVIOLATIONS_UNAUDITED,POLICYVIOLATIONS_WARN,PROJECT_ID,SUPPRESSED,UNASSIGNED_SEVERITY,VULNERABILITIES) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)" failed : Transaction (Process ID 176) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. at org.datanucleus.api.jdo.JDOAdapter.getJDOExceptionForNucleusException(JDOAdapter.java:608) at org.datanucleus.api.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:702) at org.datanucleus.api.jdo.JDOPersistenceManager.makePersistent(JDOPersistenceManager.java:722) at org.dependencytrack.tasks.metrics.ComponentMetricsUpdateTask.lambda$updateMetrics$2(ComponentMetricsUpdateTask.java:163) at alpine.persistence.AbstractAlpineQueryManager.lambda$runInTransaction$6(AbstractAlpineQueryManager.java:564) at alpine.persistence.Transaction.call(Transaction.java:139) at alpine.persistence.AbstractAlpineQueryManager.callInTransaction(AbstractAlpineQueryManager.java:542) at alpine.persistence.AbstractAlpineQueryManager.runInTransaction(AbstractAlpineQueryManager.java:563) at alpine.persistence.AbstractAlpineQueryManager.runInTransaction(AbstractAlpineQueryManager.java:575) at org.dependencytrack.tasks.metrics.ComponentMetricsUpdateTask.updateMetrics(ComponentMetricsUpdateTask.java:155) at org.dependencytrack.tasks.metrics.ProjectMetricsUpdateTask.updateRegularProjectMetrics(ProjectMetricsUpdateTask.java:130) at org.dependencytrack.tasks.metrics.ProjectMetricsUpdateTask.updateMetrics(ProjectMetricsUpdateTask.java:79) at org.dependencytrack.tasks.metrics.ProjectMetricsUpdateTask.inform(ProjectMetricsUpdateTask.java:58) at alpine.event.framework.BaseEventService.lambda$publish$0(BaseEventService.java:110) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.base/java.lang.Thread.run(Unknown Source) Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: Transaction (Process ID 176) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:276) at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1787) at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.doExecutePreparedStatement(SQLServerPreparedStatement.java:688) at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement$PrepStmtExecCmd.doExecute(SQLServerPreparedStatement.java:607) at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7745) at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:4700) at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeCommand(SQLServerStatement.java:321) at com.microsoft.sqlserver.jdbc.SQLServerStatement.executeStatement(SQLServerStatement.java:253) at com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement.executeUpdate(SQLServerPreparedStatement.java:549) at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61) at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java) at org.datanucleus.store.rdbms.SQLController.doExecuteStatementUpdate(SQLController.java:465) at org.datanucleus.store.rdbms.SQLController.executeStatementUpdateDeferRowCountCheckForBatching(SQLController.java:415) at org.datanucleus.store.rdbms.request.InsertRequest.execute(InsertRequest.java:532) at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.insertObjectInTable(RDBMSPersistenceHandler.java:235) at org.datanucleus.store.rdbms.RDBMSPersistenceHandler.insertObject(RDBMSPersistenceHandler.java:211) at org.datanucleus.state.StateManagerImpl.internalMakePersistent(StateManagerImpl.java:4610) at org.datanucleus.state.StateManagerImpl.makePersistent(StateManagerImpl.java:4587) at org.datanucleus.ExecutionContextImpl.persistObjectInternal(ExecutionContextImpl.java:2077) at org.datanucleus.ExecutionContext.persistObjectInternal(ExecutionContext.java:320) at org.datanucleus.ExecutionContextImpl.persistObjectWork(ExecutionContextImpl.java:1925) at org.datanucleus.ExecutionContextImpl.persistObject(ExecutionContextImpl.java:1786) at org.datanucleus.api.jdo.JDOPersistenceManager.jdoMakePersistent(JDOPersistenceManager.java:697) ... 15 common frames omitted

This seems to hinder the metrics update of different components.

Steps to Reproduce

We deployed the service in 2022 and have since been using the same database instance. It seems that update after update affected the database and caused data inconsistency.

We are currently running version 4.13.5.

Expected Behavior

It should update the data in the database without issues.

Dependency-Track Version

4.13.5

Dependency-Track Distribution

Container Image

Database Server

Microsoft SQL Server

Database Server Version

15.0.4445.1

Browser

N/A

Checklist

LearningEntity avatar Nov 03 '25 15:11 LearningEntity

So the first error can occur when you delete a component (or a project that the component belongs to) while a metrics update is in progress. Does this happen every time metrics are being updated?

As for the deadlock, please try enabling READ_COMMITTED_SNAPSHOT transaction isolation: https://docs.dependencytrack.org/getting-started/database-support/#examples

It is recommended to set the default transaction isolation for the Dependency-Track database to READ_COMMITTED_SNAPSHOT in order to avoid deadlocks. This can be achieved by executing the following SQL statement:

ALTER DATABASE dtrack SET READ_COMMITTED_SNAPSHOT ON;

nscuro avatar Nov 03 '25 15:11 nscuro

We already set the parameter READ_COMMITTED_SNAPSHOT on the database. It did not change the observation. This occurs every time the metrics are being updated. We are not deleting components or projects during the metrics update.

LearningEntity avatar Nov 04 '25 09:11 LearningEntity

Ok, can you check if there are any orphaned records in the DEPENDENCYMETRICS table?

select "COMPONENT_ID", count(*)
from "DEPENDENCYMETRICS" as dm
where not exists(select 1 from "COMPONENT" where "ID" = dm."COMPONENT_ID")
group by "COMPONENT_ID";

Even if there are, it would be odd that they would cause FK violations on new inserts. But I am not too familiar with MSSQL and how it evaluates constraints.

nscuro avatar Nov 04 '25 10:11 nscuro

Thank you for the query. Unfortunately there are no orphaned records.

LearningEntity avatar Nov 06 '25 15:11 LearningEntity