Skip to content

snapshot restore crashes the app when an archive has duplicate panel IDs #229

Description

@arzafran

Problem

programa snapshot restore can kill the app instead of recovering it. If an archived snapshot in session-history/ contains two panels sharing a UUID, window reconstruction reaches Dictionary(uniqueKeysWithValues:) at Sources/Workspace+Persistence.swift:104, which traps on duplicate keys, and the app dies on a fatal error.

This is the command you reach for when a layout is already lost, so crashing here costs more than a crash anywhere else.

v2SnapshotRestore (Sources/TerminalController+Snapshot.swift:30-60) checks that the file decodes, that version matches the current schema, that windows is non-empty, and since #228 it clamps the window count. It never checks that panel IDs are unique within a workspace.

The same trap is reachable from startup restore reading session-<bundleId>.json, so this is not new behaviour. Snapshot restore adds a second door to it, and a worse one, because the input is a file the user may have been editing by hand while trying to recover.

Repro

  1. Launch programa, let it save a session, then relaunch so the file is archived into ~/Library/Application Support/programa/session-history/.
  2. Open the newest archive and duplicate one entry inside a workspace's panels array, keeping the id identical.
  3. Run programa snapshot restore <id> for that archive.
  4. The app terminates on a duplicate key fatal error instead of returning an error.

Fix sketch

Validate the decoded snapshot before handing windows to createMainWindow: reject workspaces whose panels contain repeated IDs and return an invalid_params error, or de-duplicate and keep the first. Putting it in one shared validator would cover the startup path at the same time.

Found while reviewing #228.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions