deepseek-ai/deepseek-harness · error

conversation.serializeDraftImages: one or more draft images

Error message

conversation.serializeDraftImages: one or more draft images are no longer available

What it means

serializeDraftImages() resolves ordered draft ids to base64 wire payloads for slash-command submission (the composer releases images only after the command settles successfully). Like sendSession, any id that no longer lives in draftAttachments throws immediately — the command is never sent with a partial image set.

Source

Thrown at packages/client/ui-conversation/src/client/service.ts:203

    const attachments: ComposerAttachment[] = []
    for (const id of ids) {
      const attachment = this.draftAttachments.get(id)
      if (attachment !== undefined) attachments.push(attachment)
    }
    return attachments
  }

  /**
   * Serialize ordered draft images to command-submit wire payloads without
   * sending or releasing them (the composer releases only after the command
   * settles successfully).
   * @param imageIds - ordered draft-local attachment ids.
   * @returns base64 payloads in id order.
   */
  async serializeDraftImages(imageIds: readonly DraftAttachmentId[]): Promise<readonly SubmitImageAttachment[]> {
    const attachments = this.draftImages(imageIds)
    if (attachments.length !== imageIds.length) {
      throw new Error('conversation.serializeDraftImages: one or more draft images are no longer available')
    }
    return Promise.all(attachments.map(attachment => this.encodeImage(attachment.file)))
  }

  /**
   * Release one browser-owned draft image and preview URL.
   * @param id - draft attachment id.
   */
  releaseDraftImage(id: DraftAttachmentId): void {
    const attachment = this.draftAttachments.get(id)
    if (attachment === undefined) return
    this.draftAttachments.delete(id)
    this.createdImageUrls.delete(attachment.previewUrl)
    revokePreview(attachment.previewUrl)
  }

  /**
   * Release a set of browser-owned draft images.

View on GitHub (pinned to b150a551b8)

Solutions

  1. Validate id liveness (draftImages length check) and refresh the id list from the composer before serializing
  2. Retry the command without the released images if the command tolerates an empty image set
  3. Audit the release policy so images release exactly once, on settle
Defensive patterns

Strategy: validation

Validate before calling

const live = service.draftImages(imageIds)
if (live.length !== imageIds.length) {
  throw new Error('image no longer attached; re-attach before submitting')
}
return service.serializeDraftImages(live.map(a => a.id))

Prevention

When it happens

Trigger: A slash-command submit carrying images where an id was already released: an earlier successful command released its images, the chip was removed mid-flight, or the ids predate a remount of the runtime that owns attachments.

Common situations: Retrying a command whose first run released the images on success; UI chip state drifting from the runtime attachment map after a failed outcome kept the draft.

Related errors


AI-assisted analysis of deepseek-ai/deepseek-harness@b150a551b8 (2026-08-24). Data as JSON: /api/errors/9918831e7635ced1. Report an issue: GitHub.