1. Symptoms
After upgrading to macOS Golden Gate 27.0 Developer Beta 2 (Build 26A5368g), my MacBook began running extremely hot and the battery drained rapidly. I checked the process status in Terminal:
$ ps aux | grep appstoreagent
<username> 19002 107.0 0.1 488771680 25088 ?? R 12:20AM 14:55.36 /System/Library/PrivateFrameworks/AppStoreDaemon.framework/Support/appstoreagent
Even though the App Store app was not open, the appstoreagent daemon continuously consumed more than 100% of one CPU core. Force-quitting it did not help: the process was relaunched immediately and returned to full load.
2. Tracing the Logs and Finding the Root Cause
To identify the actual failure, I queried macOS Unified Logging for messages from this process:
$ /usr/bin/log show --predicate 'process == "appstoreagent" and eventMessage contains "recent_launch_times"' --last 5m
The command produced the following error:
2026-07-04 00:34:55.462135+0800 0x7969e Error 0x0 19002 0 appstoreagent: (libsqlite3.dylib) [com.apple.libsqlite3:logging] no such column: active_launch_events.recent_launch_times in "SELECT active_launch_events.ROWID, active_launch_events.bundle_id, active_launch_events.containing_bundle_id, active_launch_events.event_source, active_launch_events.is_extension, active_launch_events.launch_end_time, active_launch_events.launch_start_time, active_launch_events.recent_launch_times, active_launch_events.timestamp, active_launch_events.payload FROM active_launch_events"
What the error indicates
- Root cause: while macOS Golden Gate 27.0 Beta 2 builds or migrates the security database schema in memory, its upgrade migration appears to omit the
recent_launch_timescolumn from the physicalactive_launch_eventstable. - Why CPU usage spikes: because the column is missing, the underlying SQLite query repeatedly throws a
no such columnerror. After catching the error,appstoreagentimmediately retries at high frequency with no delay, creating a query-fail-retry loop that saturates one CPU core.
3. Why a Normal Kill Does Not Fix It
On macOS, appstoreagent is a user agent managed by the system’s root launchd daemon.
When you force-quit it with kill -9:
- The process exits and briefly releases the CPU.
launchddetects that the managed service exited unexpectedly and immediately relaunches it.- The new
appstoreagentinstance runs the same database initialization query, hits the missing-schema error again, and returns to 100% CPU usage.
Force-quitting the process therefore creates a repeated launch-crash-relaunch cycle, adding system overhead and generating large volumes of logs.
4. A SIGSTOP / SIGCONT Workaround
Because the system’s read-only volume is protected by SIP (System Integrity Protection), a regular user cannot directly repair the underlying database schema. A temporary behavioral workaround is therefore the practical option.
The strategy is to control the process with signals and suspend it.
- Send
SIGSTOP: this places the process in theT(stopped) state. macOS stops scheduling CPU time for it, so CPU usage immediately falls to 0%. Crucially,launchdstill considers the process alive and does not relaunch it. - Send
SIGCONT: when you need the App Store, this signal resumes the process immediately so downloads and updates can work normally.
The following Python 3 daemon, guardian.py, automates this behavior:
#!/usr/bin/env python3
import subprocess
import time
import os
import sys
import signal
def get_pids(process_name):
"""Return all PIDs for the specified process name."""
try:
output = subprocess.check_output(["pgrep", "-x", process_name], text=True)
return [int(pid.strip()) for pid in output.strip().split("\n") if pid.strip()]
except subprocess.CalledProcessError:
return []
def is_app_store_running():
"""Check whether the App Store GUI client is running."""
return len(get_pids("App Store")) > 0
def get_process_state(pid):
"""Return the process state. 'T' means stopped; other values mean running."""
try:
output = subprocess.check_output(["ps", "-o", "state", "-p", str(pid)], text=True)
lines = output.strip().split("\n")
if len(lines) > 1:
return lines[1].strip()
except subprocess.CalledProcessError:
pass
return None
def main():
print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] appstoreagent guardian daemon started.")
while True:
try:
agent_pids = get_pids("appstoreagent")
app_store_active = is_app_store_running()
for pid in agent_pids:
state = get_process_state(pid)
if not state:
continue
# Resume appstoreagent when the App Store is open and the process is stopped.
if app_store_active:
if 'T' in state:
print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] App Store is running. Resuming appstoreagent (PID {pid})...")
os.kill(pid, signal.SIGCONT)
# Suspend appstoreagent when the App Store is closed and the process is running.
else:
if 'T' not in state:
print(f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] App Store is closed. Suspending appstoreagent (PID {pid}) to save CPU...")
os.kill(pid, signal.SIGSTOP)
except Exception as e:
print(f"Error in guardian loop: {e}", file=sys.stderr)
time.sleep(5)
if __name__ == "__main__":
main()
5. Running the Guardian Silently with launchd
To keep the guardian running silently in the background, package it as a macOS Launch Agent.
5.1 Create the Configuration File
Create com.user.appstoreagent-guardian.plist locally:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.user.appstoreagent-guardian</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python3</string>
<string>-u</string>
<string>/path/to/guardian.py</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/path/to/guardian.log</string>
<key>StandardErrorPath</key>
<string>/path/to/guardian.err</string>
</dict>
</plist>
[!WARNING] Replace
/path/to/guardian.pyand the other example paths with absolute paths on your Mac. The-uoption is strongly recommended so Python writes unbuffered output toguardian.logimmediately.
5.2 Load and Activate the Service
- Make the guardian script executable:
chmod +x /path/to/guardian.py - Copy the configuration file into the user’s LaunchAgents directory:
cp com.user.appstoreagent-guardian.plist ~/Library/LaunchAgents/ - Load and bootstrap the guardian with
launchctl:launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.user.appstoreagent-guardian.plist - Verify the service status:
launchctl print gui/$(id -u)/com.user.appstoreagent-guardian
If the output shows state = running and the expected PID, deployment succeeded. While the App Store is closed, appstoreagent should appear as T (stopped) in ps aux, with CPU usage holding at 0.0%. Opening the App Store immediately wakes the process so it can provide normal service.
5.3 Remove the Service
After Apple ships a later beta that fixes the schema-migration bug, remove this temporary guardian with the following commands:
# Stop the background service
launchctl bootout gui/$(id -u)/com.user.appstoreagent-guardian
# Remove the configuration file
rm ~/Library/LaunchAgents/com.user.appstoreagent-guardian.plist
