cjpais/Handy · error
failed to create copy last transcript item
Error message
failed to create copy last transcript item
What it means
Panic when MenuItem::with_id fails to create the 'copy_last_transcript' item. Same muda failure family as the other tray items: the menu subsystem cannot allocate the item — duplicated id, invalid id/label, or the tray being rebuilt while the app handle is tearing down. Immediately after this line, menu assembly also queries TranscriptionManager state, but that is unrelated to the creation failure.
Solutions
- Keep 'copy_last_transcript' unique within the menu build
- Coalesce tray rebuilds triggered in quick succession and cancel pending rebuilds at shutdown
- Degrade gracefully: log and omit the item — copy-last-transcript is also reachable from history
Example fix
// before
let copy_last_transcript_i = MenuItem::with_id(
app,
"copy_last_transcript",
&strings.copy_last_transcript,
true,
None::<&str>,
)
.expect("failed to create copy last transcript item");
// after — non-fatal creation, menu omits the item on failure
let copy_last_transcript_i =
match MenuItem::with_id(app, "copy_last_transcript", &strings.copy_last_transcript, true, None::<&str>) {
Ok(item) => Some(item),
Err(e) => {
log::warn!("copy-last-transcript item omitted: {e}");
None
}
}; Defensive patterns
Strategy: fallback
Try / catch
let copy_last_transcript_i =
match MenuItem::with_id(app, "copy_last_transcript", &strings.copy_last_transcript, true, None::<&str>) {
Ok(item) => Some(item),
Err(e) => {
log::warn!("copy-last-transcript tray item skipped: {e}");
None
}
}; Prevention
- Treat transcript-access tray items as skippable since history offers the same function
- Debounce tray rebuilds triggered by theme changes or Secure Input toggling
- Log item id and error on creation failure to make field reports actionable
When it happens
Trigger: Tray menu build where MenuItem::with_id(app, "copy_last_transcript", strings.copy_last_transcript, true, None) errors — id collision or rebuild racing shutdown.
Common situations: Frequent tray refreshes (theme changes, Secure Input toggling on/off forcing menu rebuilds) overlapping quit; forks renaming/duplicating the item id.
Related errors
- failed to create check updates item
- failed to create settings item
- failed to create version item
- failed to create cancel item
- failed to create menu
AI-assisted analysis of cjpais/Handy@fbd4e15fa1 (2026-08-17).
Data as JSON: /api/errors/927dae38a4ddea49.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/src/tray.rs:238
}
/// Re-syncs the tray after something other than the recording state changed
/// (theme, Secure Input warning). The recording state itself is preserved.
pub fn refresh_tray_icon(app: &AppHandle) {
sync_tray(app);
}
/// Re-syncs the tray after something the menu depends on changed (model
/// list/selection/loaded state, language, settings).
pub fn update_tray_menu(app: &AppHandle) {
sync_tray(app);
}
/// Records the current desired tray state and schedules one apply on the main
/// thread (or lets an already-pending apply pick it up). Never blocks on the
/// main thread.
///
/// The snapshot (settings, model list, loaded state) is computed on the
/// *calling* thread on purpose: the main-thread applier must not take manager
/// locks that a worker may hold across slow work (see #1716).
pub fn sync_tray(app: &AppHandle) {
sync_tray_with(app, |_| {});
}
fn sync_tray_with(app: &AppHandle, update: impl FnOnce(&mut TrayInner)) {
let Some(state) = app.try_state::<TrayState>() else {
return;
};
// Record intent and claim a sequence number in one critical section, so
// sequence order == the order in which state changes were requested.
let (seq, icon_state) = {
let mut inner = state.lock();
update(&mut inner);
inner.next_seq += 1;
(inner.next_seq, inner.icon_state)View on GitHub (pinned to fbd4e15fa1)