# Troubleshooting Common problems and how to fix them. ## Quick Checks Before diving in, check these basics: - The app is minimized to **system tray**, not closed — right-click tray icon to quit - Your user profile has **write access** to the config folder — `%APPDATA%\PresenceJam\` (Windows), `~/Library/Application Support/PresenceJam/` (macOS), `$XDG_CONFIG_HOME/PresenceJam/` (Linux) - You're connected to the **same network** (no corporate proxy blocking Spotify/Teams APIs) - Both **Spotify Premium** and **Microsoft 365 Teams** accounts are active ## First run on macOS and Linux ### macOS: the app is blocked as an unidentified developer **Cause:** the DMG is unsigned (Apple Developer Program enrollment is out of scope — see issue #90), so Gatekeeper refuses the first launch. **Fix:** right-click the app → **Open**, or System Settings → Privacy & Security → **Open Anyway**. Subsequent opens work without the prompt. The same applies after an update, because updated `.app` builds are unsigned too. ### Linux: no tray icon and no window **Cause:** the app is tray-only, so on a desktop that cannot show tray icons it looks like nothing started. GNOME needs the AppIndicator extension, and the tray library (`libayatana-appindicator3`) must be installed; a Wayland session without the extension shows nothing at all. **Fix:** install `libayatana-appindicator3` for your distro and enable the GNOME AppIndicator extension (or use a desktop with a native tray), then re-launch the binary — a running instance is raised rather than a second one started. If the tray library is missing entirely, tray setup can fail rather than degrade, so installing the package above is the fix (issue #927 tracks making that failure graceful). See **Linux: System Keyring Required** in SETUP.md for the other Linux prerequisite. ## Spotify ### "Spotify not connected" after entering credentials **Cause:** The Redirect URI in your Spotify app isn't configured correctly. **Fix:** 1. Go to [Spotify Developer Dashboard](https://developer.spotify.com/dashboard) 2. Select your app → **Edit Settings** 3. Under **Redirect URIs**, add: `presencejam://callback` 4. Save settings 5. Restart the app and try again ### Authorization browser doesn't open **Cause:** Popup blocker or browser preference. **Fix:** 1. Check if a popup was blocked in your browser 2. Retry **Connect Spotify** (or **Reconnect** in Settings) — the app hands the authorization URL to your default browser. If that handoff fails you'll see a `Failed to open browser` warning from `[CMD.SPOTIFY_AUTH]` in the in-app **Log Viewer** (see [Logs](#logs)) 3. If it still doesn't work, paste the full redirect URL manually when prompted — see [Paste URL but nothing happens](#paste-url-but-nothing-happens) ### Paste URL but nothing happens **Cause:** The redirect URL might not have been captured automatically. **Fix:** 1. After authorizing Spotify, your browser will redirect to `presencejam://callback?code=XXX...` 2. Copy the **full URL** from your browser's address bar 3. Paste it into the app's manual URL input field 4. Click Submit ### Token refresh failures **Cause:** Spotify credentials expired or changed. **Fix:** In Settings click **Reconnect** next to Spotify and complete the browser sign-in. You only need to reconnect when the refresh itself fails (invalid grant / revoked credentials); transient network/5xx errors retry automatically. ### Tray playback controls do nothing ("no active device") **Cause:** Spotify has no active playback device — the player commands act on the active device, and there isn't one. **Fix:** Open the tray menu → **Devices** and pick a device — PresenceJam transfers playback there and starts it. Alternatively, start playback on a device first (e.g. in the Spotify app), then retry. ### Tray playback controls fail with a 403 **Cause:** Playback control requires a **Spotify Premium** subscription (a Spotify platform restriction), or the stored token predates the `user-modify-playback-state` scope. **Fix:** Check your Spotify plan. If you have Premium but the controls still fail, reconnect Spotify once (see the next entry) so the token carries the new scope. ### Tray Shuffle / Repeat does nothing, or asks for Premium **Cause:** Both are real Spotify player commands, so they carry exactly the same requirements as Play/Pause: a **Spotify Premium** account, the `user-modify-playback-state` scope (a one-time reconnect for tokens that predate it), and an **active device**. **Fix:** 1. If an in-app toast reads **"Playback control requires Spotify Premium"**, check your Spotify plan — playback control is a Premium-only Web API surface. 2. If it reads **"No active playback device - pick one from the tray Devices menu"**, open tray → **Devices** and pick one, or start playback on a device first. 3. If nothing happens and no toast appears, the stored token predates the playback scope — click **Reconnect** once (see *"Playback control needs a one-time reconnect" banner* above). The **Repeat** item spells its mode out — `Repeat: Off` → `Repeat: Context` → `Repeat: Track` → back to off — because a check mark alone cannot distinguish *context* from *track*. A command Spotify rejects leaves the label and check mark where they were, so the menu never claims a state that was refused. ### "Playback control needs a one-time reconnect" banner **Cause:** Tray playback control needs the `user-modify-playback-state` scope, which older stored tokens don't carry — a token granted before that scope was added can't control playback until you re-auth. **Fix:** Click **Reconnect** in the banner (or Settings → reconnect Spotify) once. You only need to do this once after upgrading. ### "Spotify secret conflict" banner in Settings **Cause:** A legacy plaintext `spotify.client_secret` left in `config.json` disagrees with the value stored in the OS keychain (#376). The app keeps the plaintext (nothing is deleted) and asks you to resolve it. **Fix:** Click **Reconnect** in the banner (or Settings → reconnect Spotify) once — the fresh sign-in reconciles the stored secret and the banner dismisses on reconnect. ### Reconnect shows "Keychain unavailable" **Cause:** The stored token encryption key is present but unreadable — a corrupted keychain entry, a partial write, or a key that no longer matches the `tokens.json` nonce. The app cannot decrypt the token file, so it cannot sync. **Fix:** both the Reconnect view (its corrupt-key banner) and the Diagnostics page's connections card offer **Reset local token storage** (the `reset_local_token_storage` command). It is main-window-only, runs the reset behind an arm/confirm pair, deletes the keychain entries and the encrypted `tokens.json` sidecar, and finishes with the re-sign-in prompt — you will need to connect Spotify and Teams again. Nothing else in your configuration is touched. After the reset, sign in through **Reconnect** rather than the onboarding wizard: the wizard's cache is invalidated, but the reconnect flow re-probes the keychain on every entry. **Cause:** The OS keychain could not be read — typically a locked Secret Service keyring on Linux, or a denied credential store. This is **not** the same as "no stored credential": your Spotify Client Secret is still in the keychain, the app just cannot reach it right now. Treating the two alike is what used to push a fully set-up user back through the Spotify wizard. **Fix:** 1. On Linux, unlock your keyring and make sure a Secret Service daemon is running — see [SETUP.md — Linux: System Keyring Required](./SETUP.md#linux-keyring). On Windows/macOS an unavailable store usually means the credential manager is locked by policy. 2. Re-enter the Reconnect view: it re-probes the keychain on every entry. 3. There is deliberately **no Reconnect button** while this state is showing — the sign-in flow reads the secret from the same keychain that cannot answer, so it would only open a browser window that fails. You do **not** need to re-enter your Client ID/Secret. Settings shows the same state on the credential row ("System keychain unavailable — it may be locked or missing…"). A genuine *absent* credential is the only case that offers **Run Onboarding**. ## Microsoft Teams ### "Teams not updating" after connecting **Cause:** Token expired, or the Microsoft account differs from Teams account. 1. Verify you're signed into the same Microsoft account in the app and in Teams 2. Go to Settings → **Reconnect** next to Teams → complete the device-code sign-in 3. Check the in-app log viewer for specific API error codes ### Device code sign-in times out **Cause:** The sign-in window for entering the code expired. **Fix:** 1. While the code is still valid, the app shows a live countdown of the remaining time (#429) 2. If the code expired, the app shows an expired state — click **Get new code** (or "Sign in with Microsoft" again) for a fresh code 3. Complete the sign-in before the countdown runs out 4. Make sure you're visiting the correct verification URL ### Sign-in loop / "authorization_declined" **Cause:** You declined the authorization request, or the code was entered incorrectly. **Fix:** 1. Click "Sign in with Microsoft" again for a fresh code and URL 2. Make sure to enter the code exactly as shown (uppercase, no spaces) ### "Presence features need a one-time Teams reconnect" banner **Cause:** The **Settings → Presence** toggles need the `Presence.Read` (presence gating) and `profile` (object-id claim for availability sync) scopes, which older stored tokens don't carry — so the toggles won't take effect until you re-auth. **Fix:** Click **Reconnect** in the banner (or Settings → reconnect Teams) once. You only need to do this once after upgrading. ## App Behavior ### App "closes" on X button but keeps running **This is by design.** The app minimizes to the system tray to keep syncing in the background. **To fully quit:** - Right-click the tray icon → **Quit** Closing the window is not an exit: the close button only hides the app to the tray, where it keeps polling Spotify and keeps writing your Teams status. **No tray icon?** On GNOME without the AppIndicator extension (or a host missing `libayatana-appindicator3`) there is no tray to minimize to, so the app closes the window for real instead and quits — sync stops with it — and shows a notification saying so plus how to get the tray back (issue #819). To restore the tray, install `libayatana-appindicator3` for your distro and enable the GNOME AppIndicator extension, then re-launch — see [Linux: no tray icon and no window](#linux-no-tray-icon-and-no-window). Closing without a tray is a full quit: re-launch the app to start a fresh session. **To prevent it from starting automatically:** - Turn off **Launch at Login** in Settings. The login entry it writes is the Windows/macOS login item or `~/.config/autostart/PresenceJam.desktop` on Linux; delete that file if the app is already uninstalled. ### A detached Logs/Settings window disappeared **Cause:** The pane was popped out into its own window (`logs-detached` / `settings-detached`) and the window was closed or lost behind others. **Fix:** The main window's nav still shows the pane with a dot badge while it's detached — clicking it focuses the detached window. If the detached window was closed entirely, click **Logs**/**Settings** in the main nav to re-open the view in-window, then pop it out again if you want. ### The interface is in the wrong language **Cause:** The language picker (Settings → Appearance → Language) defaults to your browser/OS language and persists the choice. **Fix:** Pick one of the eight interface languages in Settings → Appearance: **English**, **Deutsch**, **Français**, **Español**, **Italiano**, **Polski**, **Português (Brasil)** or **Nederlands**. The choice applies immediately and persists across restarts. Rust-side error strings surfaced by the backend remain English by design — only UI strings are localized. ### "Install on quit" seemed to do nothing **Cause:** With *Install on quit*, the update is applied while the app is exiting — there is no window left to show progress or an error in. If staging or applying fails at that point, the failure is visible **only in the log file** (`PresenceJam.log`), not in the UI (#244). **Fix:** Quit again (or relaunch) and check `PresenceJam.log` for `[UPDATER]` lines. If the staged update keeps failing, use **Download & Install** from the update banner instead — that path reports errors in-app. Note: since v4.2.0, a staged update that is stale (same version or older than your current install) is *deliberately* skipped with an `[UPDATER]` log line, not installed — the banner shows a skipped state with an **Install anyway** override (#431). Downgrades are off by default (`allowDowngrades: false`). ### The app came up with default settings **Cause:** `config.json` no longer parsed as JSON, so PresenceJam refused to load it. Instead of overwriting a file it cannot read, it **renames the broken file next to itself as `config.json.bak`**, logs a `[CFG] corrupt config '…' quarantined to '…'` warning, and starts on the shipped defaults. **Fix:** 1. Look for that `[CFG]` line in the log viewer — it names both the original and the backup. The **Diagnostics** page (🩺 in the Dashboard header) shows an amber *Settings were reset* banner for this too — and it keeps showing it on later launches, naming the backup file, because the per-process log line is gone by then. 2. Your old settings are all still in the `.bak`. Repair the JSON by hand and put it back as `config.json`, or simply re-apply the settings in the app. 3. Where to look (the backup sits beside the config file): | OS | Path | |----|------| | Windows | `%APPDATA%\PresenceJam\config.json.bak` | | macOS | `~/Library/Application Support/PresenceJam/config.json.bak` | | Linux | `$XDG_CONFIG_HOME/PresenceJam/config.json.bak` (usually `~/.config/PresenceJam/`) | The backup name is fixed — `config.json.bak`, never timestamped — and the rename is best-effort: if it fails, the app logs that too and still boots on defaults, leaving your original file untouched. `tokens.json` is unaffected and lives in a different folder entirely (see [SETUP.md — What Gets Installed](./SETUP.md#what-gets-installed)). The banner names the `.bak` when one is still on disk. When the banner appears **without** a backup name, the rename could not move your file — so the unreadable original is still there as `config.json`, and the banner says exactly that. ### No status appears on Teams 1. Check the Dashboard shows both Spotify and Teams as connected (green badges) 2. Start playing a track on Spotify 3. Wait for the next poll: with a track playing, the status updates within a few seconds; when nothing is playing, the app backs off between polls (30 s → 60 s → 120 s → 300 s), so an idle app can take up to five minutes to react. Failed polls retry after ~30 s (±20%) 4. If still nothing, check the log viewer for API errors **Suppressed by status rules or a presence policy?** PresenceJam also skips the write on purpose, and the Dashboard chip now names the cause: | Chip | Cause | |------|-------| | *quiet hours are active* | a quiet-hours entry covers the current time and weekday | | *a track rule matched* | an enabled quiet-hours row or track rule whose **Post this instead** field is left empty | | *you set a status message by hand* | **Never overwrite a status I set by hand** is on and your Teams status is not one the app posted (or it has expired) | | *you are out of office* | **Pause while I am out of office** is on and Teams reports you out of office | | *busy, in a call, or presenting* | the meeting/call/DND gate — busy, Do Not Disturb, focusing, in a meeting, in a call, or presenting | The log records the same verdicts — `[POLLING] process_track: quiet hours active, skipping status write`, `… track rule matched, …`, and `… presence-gated, skipping status write` for the policies. Nothing is paused *by these rules*: the app keeps polling on its normal cadence and the write resumes by itself once the cause clears (a quiet window ending, your presence going available, or the hand-set message expiring) — the one exception is a quiet-hours row with **Stop polling during this window** ticked, which pauses polling for that window only (see [USAGE.md — Status rules](./USAGE.md#status-rules)). Open **Settings → Status rules** for the first two, **Settings → Presence** for the policies (see [USAGE.md — Status rules](./USAGE.md#status-rules)). ### Status doesn't clear when Spotify is paused **Cause:** The `clear_on_pause` config option may be disabled, or you're using Spotify Web Player instead of the desktop app. **Fix:** 1. Open `config.json` and check `teams.clear_on_pause` is `true` — there is no Settings toggle for it 2. Ensure you're using the Spotify desktop app (not web player) — the API detects both, but desktop is more reliable ### Status shows but disappears quickly **Cause:** PresenceJam sets a playing track's status expiry (`expiryDateTime`) to the track's end time plus a buffer (default 10 s; `polling.expiry_buffer_seconds` in `config.json`). When the track ends, pauses, or stops, the app replaces the status on the next poll with the pause/stop placeholder — by default `Paused` and `Nothing playing on Spotify`, both posted with the 🎵 prefix — and that placeholder has its **own fixed 60 s expiry** (`placeholder_expiry_str()`), so it self-removes about a minute after posting. Since 4.7 both texts are yours to edit (`teams.paused_status_format` / `teams.stopped_status_format`, Settings → Status rules → *Pause and stop status text*; clearing a field restores the default). There is no server-side 24-hour cap — the Teams client's "Clear status message after" dropdown (which includes 24 h) affects only messages you set in the Teams UI, not Graph-set messages. **Fix:** This is the app's own expiry/clear mechanism, not a Teams limitation. To keep the status visible longer, raise the buffer in `config.json` (`polling.expiry_buffer_seconds`) or set `teams.clear_on_pause` to `false` in `config.json` (there is no Settings toggle for it). ## Profanity Filter ### My custom placeholder isn't showing 1. In **Settings → Teams**, ensure **Profanity Filter** is toggled ON 2. Check that **Placeholder** field is non-empty (whitespace-only falls back to default) 3. If the placeholder contains `{emoji}`, it will be replaced with 🎵 (playing) or ⏸️ (paused) ### A profane track isn't being filtered **Cause:** The filter currently operates on the formatted status string after the template is applied. If your template uses custom placeholders, the raw track metadata (artist/track/album) may not be fully covered. **Fix / Workaround:** This is a known architectural limitation: the filter screens the formatted status string (see [the polling page](./docs/architecture/polling.md#profanity-filter)), verified against `polling/write.rs` (filter applied at the single status-write path) and `profanity.rs`. A future release will filter raw Spotify fields before formatting. ### What's in the profanity word list? The list is in `src-tauri/src/profanity.rs` and covers common English profanity. Detection includes: - Leetspeak variants: `sh1t`, `$hit`, `d@mn`, `p1ss`, `n1gg3r` - Repeated-character variants: `shiiit`, `fuuuuck` - "fucking", "fucked", "fucker" variants - Any words you add under Settings → Profanity filter → *Custom words to filter* (one per line, up to 64 entries of 32 characters). Your words go through the same boundary and evasion rules as the list above — adding `spam` does not flag `spamalot`, and `s.p.a.m` / `5pam` are still caught — and the status preview updates as soon as you type them. False positives are prevented via word-boundary checks — words like `class`, `cocktail`, `assassin`, `vacuum`, `cumulative` are not flagged. ## Logs ### Where to find logs **In-app:** the **Log Viewer** view (it can be popped out into its own window) lets you scroll through the entries without touching the filesystem. When it opens it is already backfilled with the last 500 lines of the on-disk file, so the history is there before the first new entry is logged; while you are scrolled up it holds your position as new lines arrive. **Direct filesystem** — `PresenceJam.log` plus its rotated archives, managed by the logging plugin: ``` %LOCALAPPDATA%\com.presencejam.app\logs\PresenceJam.log (Windows) ~/Library/Logs/com.presencejam.app/PresenceJam.log (macOS) ~/.local/share/com.presencejam.app/logs/PresenceJam.log (Linux) ``` The live file rotates once it reaches `logging.max_file_size_mb` (1–500 MB, default 10) and keeps `logging.keep_files` archives (1–20, default 3) — plus the live log, so the folder holds up to `keep_files + 1` files. Both are editable in Settings → Logging. The log directory is the **bundle-identifier folder** (`com.presencejam.app`) — `app_log_dir()` appends the bundle id to the platform's local data directory, so the logs do *not* sit next to `config.json` (issue #300). This is the same folder tray menu → **Open Logs Folder** opens. **From PowerShell:** ```powershell Start-Process "$env:LOCALAPPDATA\com.presencejam.app\logs" ``` ### How to read log levels | Level | What it means | |-------|---------------| | `ERROR` | Something failed — API returned error, file I/O failed | | `WARN` | Something unexpected but recoverable (e.g., slow network) | | `INFO` | Normal operations (track changed, status updated) | | `DEBUG` | Verbose — every polling iteration logged | The current log level is set in **Settings → Logging** (the same value lives in `config.json` under `logging.log_level`, default `Info`). The card's size/retention fields apply from the next launch. ### Attaching logs to bug reports 1. Open the log folder: tray menu → **Open Logs Folder** (or `%LOCALAPPDATA%\com.presencejam.app\logs` on Windows) 2. Attach `PresenceJam.log` (and, if the issue spans a longer window, the rotated archives in the same folder) 3. Note the approximate time the issue occurred ### High CPU or memory usage PresenceJam is designed to be lightweight. If you're seeing high resource usage: 1. Check only one instance is running (see system tray) 2. Verify the polling isn't stuck in a fast loop (logs will show `polling_loop: sleeping for X seconds`) 3. Close other resource-heavy applications and test again ### App starts slowly Tauri apps have a cold-start time of 1-3 seconds on first launch. This is normal — subsequent launches from the tray are faster. ## Networking ### Blocked by corporate proxy PresenceJam makes HTTPS requests directly to: - `accounts.spotify.com` - `api.spotify.com` - `login.microsoftonline.com` - `graph.microsoft.com` If you're on a corporate network that blocks these domains, the app won't work. Check with your IT administrator. ### "Connection refused" errors **Cause:** Network connectivity issue or VPN interference. **Fix:** 1. Try disabling VPN temporarily 2. Verify you can reach Spotify.com in your browser 3. Check your firewall hasn't blocked the app — Windows Defender Firewall, the macOS firewall, or a distro firewall (ufw/firewalld) ## Uninstalling To fully remove PresenceJam: 1. **Quit the app** (right-click tray → Quit) 2. **Delete the app:** - Windows: Settings → Apps → PresenceJam → Uninstall - macOS: Drag PresenceJam from Applications to Trash - Linux (deb): `sudo apt remove presence-jam` (or `sudo dpkg -r presence-jam`) - Linux (AppImage): delete the AppImage file 3. **Delete user data** (optional — removes all tokens and config). `config.json`, `tokens.json` and the logs are NOT in the same folder (issue #300), so delete all three: ``` %APPDATA%\PresenceJam\ (Windows — config.json) %APPDATA%\com.presencejam.app\PresenceJam\ (Windows — tokens.json) %LOCALAPPDATA%\com.presencejam.app\logs\ (Windows — logs) ~/Library/Application Support/PresenceJam/ (macOS — config.json) ~/Library/Application Support/com.presencejam.app/PresenceJam/ (macOS — tokens.json) ~/Library/Logs/com.presencejam.app/ (macOS — logs) ${XDG_CONFIG_HOME:-$HOME/.config}/PresenceJam/ (Linux — config.json) ${XDG_CONFIG_HOME:-$HOME/.config}/com.presencejam.app/PresenceJam/ (Linux — tokens.json) ~/.local/share/com.presencejam.app/logs/ (Linux — logs) ``` You can also use PowerShell: ```powershell Remove-Item -Recurse -Force "$env:APPDATA\PresenceJam" Remove-Item -Recurse -Force "$env:APPDATA\com.presencejam.app\PresenceJam" Remove-Item -Recurse -Force "$env:LOCALAPPDATA\com.presencejam.app\logs" ``` 4. **Remove the login entry** if **Launch at Login** was on — delete `~/.config/autostart/PresenceJam.desktop` on Linux; Windows and macOS remove it with the app. `~/.local/share/applications/presencejam.desktop` exists only if you created one for an AppImage install. Note: Your Spotify app credentials in the Spotify Developer Dashboard are unaffected.