{"record":{"id":"d039c136edd239da","repo":"iflytek/astron-agent","slug":"internal-server-error-d039c1","errorCode":"INTERNAL_SERVER_ERROR","errorMessage":"INTERNAL_SERVER_ERROR","messagePattern":"INTERNAL_SERVER_ERROR","errorType":"error_code","errorClass":"BusinessException","httpStatus":null,"severity":"error","filePath":"console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowArtifactService.java","lineNumber":265,"sourceCode":"                .map(artifact -> toDto(artifact, false))\n                .toList();\n    }\n\n    public WorkflowArtifactDto getDownloadInfo(Long artifactId) {\n        WorkflowArtifact artifact = getScopedArtifact(artifactId);\n        assertWorkflowVisible(artifact.getWorkflowId());\n        return toDto(artifact, true);\n    }\n\n    @Transactional\n    public void deleteArtifact(Long artifactId) {\n        WorkflowArtifact artifact = getScopedArtifact(artifactId);\n        assertWorkflowWritable(artifact.getWorkflowId());\n        requireArtifactObjectLocation(artifact);\n        artifact.setDeleted(Boolean.TRUE);\n        artifact.setUpdateTime(LocalDateTime.now());\n        if (!updateById(artifact)) {\n            throw new BusinessException(ResponseEnum.INTERNAL_SERVER_ERROR);\n        }\n        Runnable purge = () -> purgeDeletedArtifactObject(artifact);\n        if (TransactionSynchronizationManager.isSynchronizationActive()) {\n            TransactionSynchronizationManager.registerSynchronization(\n                    new TransactionSynchronization() {\n                        @Override\n                        public void afterCommit() {\n                            purge.run();\n                        }\n                    });\n        } else {\n            purge.run();\n        }\n    }\n\n    @Transactional\n    public WorkflowArtifactDto uploadInternal(\n            String token,","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/iflytek/astron-agent/blob/5e758547a83371a5a4b29dadf4ac03e8dd527635/console/backend/toolkit/src/main/java/com/iflytek/astron/console/toolkit/service/workflow/WorkflowArtifactService.java#L247-L283","documentation":"deleteArtifact throws INTERNAL_SERVER_ERROR when the soft-delete update (setting deleted=TRUE on the WorkflowArtifact row) reports failure via MyBatis-Plus updateById returning false. This is an unexpected persistence failure after the artifact passed scope and writability checks; the object purge is deliberately deferred via TransactionSynchronization so the object store is only cleaned after a successful commit.","triggerScenarios":"The artifact row no longer matches the update (e.g. concurrently deleted by another request between getScopedArtifact and updateById), a DB connectivity/lock-timeout failure surfaces as a 0-row update, or an optimistic-lock/version mismatch on the entity.","commonSituations":"Double-clicking delete so two requests race; database failover or connection-pool exhaustion mid-request; row deleted in another tab while this request was in flight.","solutions":["Retry the delete; verify the artifact still exists via the list endpoint first","Check DB connectivity, lock waits, and connection-pool health in the toolkit service logs","If using optimistic locking (@Version), refetch the entity before deleting to avoid stale-version updates","Add idempotency: treat 'already deleted' as success by re-querying with deleted=TRUE included"],"exampleFix":"// before\nif (!updateById(artifact)) {\n    throw new BusinessException(ResponseEnum.INTERNAL_SERVER_ERROR);\n}\n// after\nartifact = getScopedArtifactIncludingDeleted(artifactId);\nif (Boolean.TRUE.equals(artifact.getDeleted())) {\n    return; // idempotent no-op\n}\nif (!updateById(artifact)) {\n    throw new BusinessException(ResponseEnum.INTERNAL_SERVER_ERROR);\n}","handlingStrategy":"try-catch","validationCode":"// Verify the artifact exists and is undeleted before deleting\nWorkflowArtifact a = artifactApi.get(artifactId);\nif (a == null || Boolean.TRUE.equals(a.getDeleted()))\n    throw new IllegalStateException(\"Artifact already deleted: \" + artifactId);","typeGuard":null,"tryCatchPattern":"try {\n    artifactApi.delete(artifactId);\n} catch (BusinessException e) {\n    if (\"INTERNAL_SERVER_ERROR\".equals(e.getCode())) {\n        log.warn(\"Soft-delete failed for {}; retrying once\", artifactId, e);\n        artifactApi.delete(artifactId); // idempotent retry\n    } else throw e;\n}","preventionTips":["Make delete flows idempotent on the client (treat already-deleted as success)","Debounce double-clicks on delete buttons","Monitor DB health; transient write failures usually indicate connectivity/lock issues"],"tags":["java","database","mybatis-plus","soft-delete","workflow-artifact"],"backgroundTag":"database-write-failed","analyzedSha":"5e758547a83371a5a4b29dadf4ac03e8dd527635","analyzedAt":"2026-09-12T08:03:51.356Z","contentChangedAt":"2026-09-12T08:03:51.356Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}