published on 15th April 2026
The thing about a new major GNOME version is that, usually, most of the GNOME shell extensions do not support it yet when it comes out. This is certainly the case when you use GNOME on Arch, because itz soo bleeding edge !!1!!111 ;)
And even though I have been back on GNOME for a good 5 years now (previously I used dwm), I always forget to check if the extensions I’m using support the new version already. Usually I just blindly run the update and get confused when the extensions are borked after a reboot, prompting me to read the pacman logs and then construct the commands to downgrade the relevant packages. Yes I know this is unsupported….. moving on.
To stop future me from getting tripped up by this madness ever again, I wrote a shell script that checks whether your installed GNOME extensions support the next version (see at the bottom of this page, or this gist). When I was finished, I had the idea to implement it as a pacman hook, because realistically, if it’s not enforced by the package manager before an upgrade, I would forget to run it anyways.
Pacman hooks allow you inject your own logic and scripts into the package operation flow, which is perfect for this use case.
After reading man pacman-hooks:
/etc/pacman.d/hooks/90-gnome.hook
copy 1[Trigger]
2# run this hook when the gnome-shell package is being upgraded
3Type = Package
4Operation = Upgrade
5Target = gnome-shell
6
7[Action]
8Description = Checking if new gnome-shell version supports your extensions
9# run before installing
10When = PreTransaction
11# the checker script
12Exec = /usr/bin/runuser -u <YOUR_USER> -- "/usr/local/bin/check-gnome-compat.sh"
13# dependencies of the script
14Depends = jq
15Depends = curl
16# fail the pacman command if the script returns nonzero
17AbortOnFailIn line 12 replace <YOUR_USER> with your user name. The script needs to run as your user so that it can correctly resolve the installed GNOME extensions. And we also don’t want to curl to the internet as root :)
Below you can see a pacman run where the checker script successfully stopped gnome-shell version 50 from being installed because there were incompatibilities:

The way it is implemented now, pacman just aborts the whole update operation and tells you to adjust your IgnorePkg, which is fine for me. If gnome-shell is in IgnorePkg the hook will not be triggered.
And finally, here is the checker script, also hosted in this gist:
/usr/local/bin/check-gnome-compat.sh
copy 1#!/usr/bin/env bash
2# check if your enabled GNOME Shell extensions support the next GNOME version.
3# depends: curl, jq
4
5set -euo pipefail
6
7API="https://extensions.gnome.org/extension-info/?uuid="
8
9RED=$'\033[0;31m'
10GREEN=$'\033[0;32m'
11YELLOW=$'\033[0;33m'
12RESET=$'\033[0m'
13
14# get current and next version from pacman
15UPDATE_DATA=$(pacman -Qu gnome-shell 2>/dev/null) || true
16
17if [[ -z "$UPDATE_DATA" ]]; then
18 echo "Couldn't find any updates for gnome-shell."
19 exit 0
20fi
21
22# "gnome-shell 1:49.5-1 -> 1:50.0-1" — strip epoch (N:) from both sides
23# and extract major version
24GNOME_VERSION=$(echo "$UPDATE_DATA" | grep -oP '\d+(?=\.\d+-\d+ ->)')
25GNOME_VERSION_NEXT=$(echo "$UPDATE_DATA" | grep -oP '(?<=-> )[\d:]+' | sed 's/^[0-9]*://' | grep -oP '^\d+')
26
27if [[ "$GNOME_VERSION_NEXT" -le "$GNOME_VERSION" ]]; then
28 echo "No major version change ($GNOME_VERSION -> $GNOME_VERSION_NEXT), nothing to check."
29 exit 0
30fi
31
32# get extension uuids
33mapfile -t UUIDS < <(/usr/bin/gnome-extensions list --enabled)
34
35if [[ ${#UUIDS[@]} -eq 0 ]]; then
36 echo "No enabled extensions found." >&2
37 exit 1
38fi
39
40echo -e "\nGNOME $GNOME_VERSION --> $GNOME_VERSION_NEXT extension compatibility check"
41
42COMPATIBLE=0
43INCOMPATIBLE=0
44UNKNOWN=0
45
46check_extension() {
47 local uuid="$1"
48 local encoded
49 # url encode the uuid
50 encoded=$(jq --raw-input --raw-output @uri <<< "$uuid")
51 local url="${API}${encoded}"
52
53 local http_code body
54 # read extension's properties from gnome extension api
55 body=$(curl --fail --silent --show-error --max-time 10 --write-out "\n%{http_code}" "$url" 2>/dev/null) || true
56 # read http code from last line
57 http_code=$(tail -1 <<< "$body")
58 body=$(sed '$d' <<< "$body")
59
60 if [[ "$http_code" == "404" || -z "$body" ]]; then
61 echo "[${YELLOW}??${RESET}] $uuid (not found)"
62 ((UNKNOWN++)) || true
63 return
64 fi
65
66 local name has_version
67 name=$(jq --raw-output '.name // ""' <<< "$body" 2>/dev/null || echo "")
68 has_version=$(jq --raw-output --arg v "$GNOME_VERSION_NEXT" 'if .shell_version_map[$v] then "yes" else "no" end' <<< "$body" 2>/dev/null || echo "no")
69
70 local display="$uuid"
71 [[ -n "$name" ]] && display="$name ($uuid)"
72
73 if [[ "$has_version" == "yes" ]]; then
74 echo "[${GREEN}OK${RESET}] $display"
75 ((COMPATIBLE++)) || true
76 else
77 local latest_shell
78 latest_shell=$(jq --raw-output '.shell_version_map | keys | map(select(test("^[0-9]+$"))) | map(tonumber) | max // "?" | tostring' <<< "$body" 2>/dev/null || echo "?")
79 echo "[${RED}NO${RESET}] $display (latest: v$latest_shell)"
80 ((INCOMPATIBLE++)) || true
81 fi
82}
83
84for uuid in "${UUIDS[@]}"; do
85 [[ -z "$uuid" ]] && continue
86 check_extension "$uuid"
87 # dont be too quick
88 sleep 0.15
89done
90
91echo -e "\nFor GNOME $GNOME_VERSION_NEXT: $COMPATIBLE compatible, $INCOMPATIBLE incompatible, $UNKNOWN unknown"
92
93if [[ $INCOMPATIBLE -gt 0 ]]; then
94 echo -e "\n${RED}Some extensions are not compatible with the next GNOME version. Please update your IgnorePkg.${RESET}\n"
95 exit 1
96fi