larksuite/cli · error

header %q is protected; rerun with allow_protected_header_ed

Error message

header %q is protected; rerun with allow_protected_header_edits

What it means

ensureHeaderEditable rejects edits to headers listed in protectedHeaders unless PatchOptions.AllowProtectedHeaderEdits is true. The library protects structural headers (like Subject handling, MIME headers, or transport headers) from accidental modification because changing them can corrupt the draft's semantics.

Source

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

		}
		return removeInline(snapshot, partID)
	case "insert_signature":
		return insertSignatureOp(snapshot, op)
	case "remove_signature":
		return removeSignatureOp(snapshot)
	case "set_calendar":
		return applyCalendarSet(snapshot, op.CalendarICS)
	case "remove_calendar":
		return applyCalendarRemove(snapshot)
	default:
		return fmt.Errorf("unsupported patch op %q", op.Op)
	}
	return nil
}

func ensureHeaderEditable(name string, options PatchOptions) error {
	if protectedHeaders[strings.ToLower(strings.TrimSpace(name))] && !options.AllowProtectedHeaderEdits {
		return fmt.Errorf("header %q is protected; rerun with allow_protected_header_edits", name)
	}
	return nil
}

func setRecipients(snapshot *DraftSnapshot, field string, addrs []Address) error {
	field = strings.ToLower(strings.TrimSpace(field))
	if !isRecipientField(field) {
		return fmt.Errorf("recipient field must be one of to/cc/bcc")
	}
	normalized := make([]Address, 0, len(addrs))
	seen := map[string]bool{}
	for _, addr := range addrs {
		if strings.TrimSpace(addr.Address) == "" {
			return fmt.Errorf("recipient address is empty")
		}
		key := strings.ToLower(strings.TrimSpace(addr.Address))
		if seen[key] {
			continue

View on GitHub (pinned to 7fd6ef3c07)

Solutions

  1. If the edit is intentional, set PatchOptions{AllowProtectedHeaderEdits: true}.
  2. Use the dedicated ops instead of generic set_header (e.g. set_subject for Subject).
  3. Check the protectedHeaders set in patch.go to see which names require the flag.
  4. Restrict AllowProtectedHeaderEdits to trusted admin flows; keep it false by default.

Example fix

// before
err := Apply(ctx, dctx, ops, PatchOptions{})
// after
err := Apply(ctx, dctx, ops, PatchOptions{AllowProtectedHeaderEdits: true})
Defensive patterns

Strategy: validation

Validate before calling

var protectedHeaders = map[string]bool{ /* mirror patch.go set */ }
func needsProtectedFlag(name string) bool {
    return protectedHeaders[strings.ToLower(strings.TrimSpace(name))]
}

Type guard

func isEditableHeader(name string, opts PatchOptions) bool {
    return opts.AllowProtectedHeaderEdits || !protectedHeaders[strings.ToLower(strings.TrimSpace(name))]
}

Try / catch

if err := Apply(ctx, dctx, ops, opts); err != nil {
    if strings.Contains(err.Error(), "is protected") {
        return fmt.Errorf("use dedicated op or set AllowProtectedHeaderEdits=true: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Apply with a 'set_header' or 'remove_header' op whose Name (case-insensitive, trimmed) is in the protected set, without setting PatchOptions.AllowProtectedHeaderEdits.

Common situations: Trying to override headers such as MIME-Version, Content-Type, or similar structural headers via a generic header op; migrating scripts that previously rewrote these headers directly.

Related errors


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