larksuite/cli · error

inline part %q not found

Error message

inline part %q not found

What it means

replaceInline throws this when no MIME part with the given partID exists in the draft snapshot body tree. findPart walks the whole MIME tree and returns nil for unknown IDs, so the replacement target cannot be located.

Source

Thrown at shortcuts/mail/draft/patch.go:674

		container, err = ensureInlineContainerRef(containerRef)
		if err != nil {
			return nil, fmt.Errorf("inline image %q: %w", path, err)
		}
	}
	container.Children = append(container.Children, inline)
	container.Dirty = true
	return container, nil
}

func addInline(dctx *DraftCtx, snapshot *DraftSnapshot, path, cid, fileName, contentType string) error {
	_, err := loadAndAttachInline(dctx, snapshot, path, cid, fileName, nil)
	return err
}

func replaceInline(dctx *DraftCtx, snapshot *DraftSnapshot, partID, path, cid, fileName, contentType string) error {
	part := findPart(snapshot.Body, partID)
	if part == nil {
		return fmt.Errorf("inline part %q not found", partID)
	}
	if !isInlinePart(part) {
		return fmt.Errorf("part %q is not an inline MIME part", partID)
	}
	info, err := dctx.FIO.Stat(path)
	if err != nil {
		return err
	}
	if err := checkSnapshotAttachmentLimit(snapshot, info.Size(), part); err != nil {
		return err
	}
	f, err := dctx.FIO.Open(path)
	if err != nil {
		return err
	}
	defer f.Close()
	content, err := io.ReadAll(f)
	if err != nil {

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. Re-fetch the draft to get the current part list and use a fresh partID
  2. Check the partID for typos or trailing whitespace
  3. Confirm the part still exists (a prior remove operation may have deleted it)
  4. Verify you are patching the same draft the partID came from

Example fix

// before
--replace-inline part_id=old_id_123 --path ./new.png
// after
lark mail draft get --draft-id D   # look up current inline part IDs
--replace-inline part_id=current_id --path ./new.png
Defensive patterns

Strategy: validation

Validate before calling

snap, _ := draftGet(draftID)
ids := collectPartIDs(snap.Body)
if !slices.Contains(ids, partID) {
    return fmt.Errorf("part %s not in draft; have %v", partID, ids)
}

Type guard

func partExists(snap *DraftSnapshot, id string) bool {
    return snap != nil && snap.Body != nil && findPart(snap.Body, id) != nil
}

Try / catch

if err := replaceInline(...); err != nil {
    if strings.Contains(err.Error(), "not found") {
        // refetch draft and refresh partID
    }
}

Prevention

When it happens

Trigger: applyOp -> replaceInline with a partID that does not exist in the current snapshot: typo, part already removed, or partID taken from a different/stale draft snapshot.

Common situations: Script caches part IDs from an earlier fetch then re-patches after the draft changed; copying a partID from a sibling draft; case/whitespace mistakes in the ID.

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/01d2e7f78795eb15. Report an issue: GitHub.