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
- Re-fetch the draft to get the current part list and use a fresh partID
- Check the partID for typos or trailing whitespace
- Confirm the part still exists (a prior remove operation may have deleted it)
- 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
- Re-fetch the draft immediately before each patch
- Never cache part IDs across draft mutations
- Copy partIDs programmatically, not by hand
- Verify the draft ID matches the one IDs came from
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
- part %q is not an inline MIME part
- cannot remove root MIME part
- attachment part %q not found
- no part with cid %q found
- add_attachment requires path
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/01d2e7f78795eb15.
Report an issue: GitHub.