halo-dev/halo · warning · Error

Please select two snapshots to compare

Error message

Please select two snapshots to compare

What it means

Thrown in the queryFn of SnapshotDiffContent.vue when snapshotNames.length is not exactly 2. The diff view needs exactly two snapshots (new + old) to compare. Notably, the `enabled` computed only checks !!snapshotNames?.length (truthy, i.e. >=1), so selecting exactly one snapshot enables the query but the queryFn throws this message — a guard/`enabled` mismatch that surfaces the error to the user via onError → Toast.

Source

Thrown at ui/console-src/components/snapshots/SnapshotDiffContent.vue:35

const props = withDefaults(
  defineProps<{
    cacheKey: string;
    name: string;
    snapshotNames?: string[];
    getApi: (snapshotName: string) => Promise<ContentWrapper>;
  }>(),
  {
    snapshotNames: () => [],
  }
);

const { name, snapshotNames, cacheKey } = toRefs(props);

const { data: snapshot, isLoading } = useQuery({
  queryKey: SNAPSHOT_DIFF_QUERY_KEY(cacheKey, name, snapshotNames),
  queryFn: async () => {
    if (snapshotNames.value?.length !== 2) {
      throw new Error("Please select two snapshots to compare");
    }

    const newSnapshot = await props.getApi(snapshotNames.value[0]);

    const oldSnapshot = await props.getApi(snapshotNames.value[1]);

    return {
      old: oldSnapshot,
      new: newSnapshot,
    };
  },
  onError(err) {
    if (err instanceof Error) {
      Toast.error(err.message);
    }
  },
  enabled: computed(() => !!name.value && !!snapshotNames.value?.length),
});

View on GitHub (pinned to d2f5165f9c)

Solutions

  1. Fix the `enabled` predicate to require exactly two snapshots so the query never runs in a throwing state: enabled = computed(() => !!name.value && snapshotNames.value?.length === 2).
  2. Ensure the parent only mounts/renders SnapshotDiffContent once two snapshots are chosen.
  3. If you intentionally keep the throw, suppress onError when length !== 2 to avoid duplicate UX feedback (the template already handles the empty/insufficient case visually).
  4. Add a type guard at the parent boundary so snapshotNames is typed as [string, string] only when two are selected.

Example fix

// before
enabled: computed(() => !!name.value && !!snapshotNames.value?.length),
queryFn: async () => {
  if (snapshotNames.value?.length !== 2) {
    throw new Error("Please select two snapshots to compare");
  }
  ...
// after — align enabled with the queryFn's precondition
enabled: computed(() => !!name.value && snapshotNames.value?.length === 2),
Defensive patterns

Strategy: validation

Validate before calling

// Require exactly two snapshots before the diff query can run
function twoSnapshotNames(names: string[] | undefined): [string, string] | null {
  if (Array.isArray(names) && names.length === 2) return [names[0], names[1]];
  return null;
}
// use in enabled + queryFn:
// enabled: computed(() => !!name.value && twoSnapshotNames(snapshotNames.value) !== null)

Type guard

function hasTwoSnapshots(names: string[] | undefined): names is [string, string] {
  return Array.isArray(names) && names.length === 2;
}

Try / catch

onError(err) {
  // Suppress the 'select two' message here — the template already shows select_two_tip
  if (err instanceof Error && err.message !== "Please select two snapshots to compare") {
    Toast.error(err.message);
  }
}

Prevention

When it happens

Trigger: snapshotNames has length 1 (or >2): the enabled predicate is satisfied (truthy length) so useQuery runs, but queryFn asserts length === 2 and throws. Also reachable if the parent transiently passes a single-element array while the user is mid-selection, or if a snapshot list filter reduces the selection to one item reactively.

Common situations: User selects only one snapshot in the diff picker and the component renders; parent passes [onlyNew] before [old] is chosen; a watch updates snapshotNames to length 1 during reactivity churn; the diff UI is opened from a context that pre-selects a single snapshot. The onError shows 'Please select two snapshots to compare' as a toast even though the template's v-if (line 228) already shows a select-two tip — double feedback.

Related errors


AI-assisted analysis of halo-dev/halo@d2f5165f9c (2026-08-14). Data as JSON: /api/errors/bf2baa8b7a7910a5. Report an issue: GitHub.