{"record":{"id":"8eb09fba5adefe57","repo":"can1357/oh-my-pi","slug":"security-scan-options-scanid-has-already-been-p","errorCode":null,"errorMessage":"Security scan ${options.scanId} has already been published","messagePattern":"Security scan (.+?) has already been published","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/security/publication.ts","lineNumber":265,"sourceCode":"\t\t\treturn question;\n\t\t});\n\t}\n\treturn coverage;\n}\n\nexport function createSecurityPublicationTool(\n\toptions: SecurityPublicationOptions,\n): ToolDefinition<typeof securityPublishSchema, SecurityPublishDetails> {\n\tlet published = false;\n\treturn {\n\t\tname: \"security_publish\",\n\t\tlabel: \"Publish Security Scan\",\n\t\tdescription: securityPublishDescription.trim(),\n\t\tparameters: securityPublishSchema,\n\t\tapproval: \"write\",\n\t\tstrict: true,\n\t\tasync execute(_toolCallId, params) {\n\t\t\tif (published) throw new Error(`Security scan ${options.scanId} has already been published`);\n\t\t\tpublished = true;\n\t\t\tlet persisted = false;\n\t\t\ttry {\n\t\t\t\tconst completedAt = new Date().toISOString();\n\t\t\t\tconst findingsByFingerprint = new Map<string, SecurityFinding>();\n\t\t\t\tfor (const input of params.findings) {\n\t\t\t\t\tconst finding = buildFinding(input, options, completedAt);\n\t\t\t\t\tif (!findingsByFingerprint.has(finding.fingerprint)) {\n\t\t\t\t\t\tfindingsByFingerprint.set(finding.fingerprint, finding);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst findings = [...findingsByFingerprint.values()];\n\t\t\t\tconst producer = createNativeSecurityProducer();\n\t\t\t\tconst provenance = createNativeSecurityProvenance({\n\t\t\t\t\tcreatedAt: options.startedAt,\n\t\t\t\t\taccount: options.plan.account,\n\t\t\t\t\tplanFingerprint: options.plan.fingerprint,\n\t\t\t\t\tworkflowFingerprint: options.plan.workflowFingerprint,","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/security/publication.ts#L247-L283","documentation":"The security publish tool is strictly one-shot: its execute() sets a `published` flag and throws if invoked a second time for the same scanId. This guarantees a scan is published exactly once, preventing duplicate publication records and conflicting finding sets for one scan id.","triggerScenarios":"Calling the publish security scan tool a second time within the same session/plan after a successful (or flagged-in-progress) publication of the same scanId.","commonSituations":"An agent retries the publish tool because it did not parse the first result, a workflow script re-invokes the tool, or the user manually re-runs publish after already publishing findings.","solutions":["Do not call publish again; retrieve the existing publication via the store instead","Create a new scan (new scanId) and publish that if findings need re-submission","Restart the session/plan to get a fresh publish tool bound to a new scan","Check publication status before invoking publish"],"exampleFix":"// before\nawait publishTool.execute(id, params); // second call\n// after\nif (!published) await publishTool.execute(id, params); else readExistingPublication(scanId);","handlingStrategy":"try-catch","validationCode":"if (publishedScans.has(scanId)) return existingPublication;","typeGuard":"null","tryCatchPattern":"try { await publish(params); } catch (e) { if (String(e.message).includes(\"already been published\")) { /* fetch existing */ } else throw e; }","preventionTips":["Track published scanIds in workflow state","Never blind-retry publish"],"tags":["state","idempotency","security"],"backgroundTag":"already-published","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}