majorwiki/05-troubleshooting/obs-stale-script-paths-after-windows-profile-rename.md
Marcus (via Claude Code) 28518e403e Add troubleshooting articles: Netdata apps-group FD false-positive + OBS stale script paths
- netdata-apps-fds-group-false-positive: the apps_group_file_descriptors_utilization
  false 100% on forking/root app groups (tailscaled on MajorToot 2026-05-15),
  the not-a-privilege gotcha, fleet-wide silence fix in MajorAnsible.
- obs-stale-script-paths: pending from prior session (not on remote).
- SUMMARY.md: link both (re-applied onto upstream after concurrent rebase).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 03:22:12 -04:00

4.8 KiB

title domain category tags status created updated
OBS Studio — "Error opening file: (null)" After Windows Profile Rename troubleshooting streaming
obs
streaming
windows
lua
profile-migration
published 2026-05-14 2026-05-14

OBS Studio — "Error opening file: (null)" After Windows Profile Rename

Symptom

Loading a scene collection in OBS Studio triggers a popup like:

[<ScriptName>.lua] Error opening file: (null)

The (null) is the giveaway: OBS resolved the registered script path to nothing — the file doesn't exist where the scene collection says it does. Most commonly this happens after a Windows profile was renamed or migrated and C:\Users\<old>\... paths were not updated.

Why it happens

OBS stores per-scene-collection Lua/Python script registrations inside the scene collection JSON at:

%APPDATA%\obs-studio\basic\scenes\<Collection>.json

Each entry under modules.scripts-tool[] is an absolute Windows path. Renaming the Windows profile does not rewrite these — the JSON keeps pointing at the old C:\Users\<old>\... location, and OBS surfaces the resolution failure as a (null) popup on collection load.

Diagnose

From WSL (or any shell with access to %APPDATA%):

OBS_DIR="/mnt/c/Users/<current-windows-user>/AppData/Roaming/obs-studio"

# 1. List scene collections
ls "$OBS_DIR/basic/scenes/"

# 2. Find collections referencing the missing script
grep -l -i "<script-name-substring>" "$OBS_DIR/basic/scenes/"*.json

# 3. Dump the scripts-tool paths from each suspect collection
python3 -c "
import json, sys
d = json.load(open(sys.argv[1]))
for s in d.get('modules', {}).get('scripts-tool', []):
    print(s.get('path'))
" "$OBS_DIR/basic/scenes/<Collection>.json"

If a printed path contains C:/Users/<old-username>/... and the file doesn't exist on disk, you've found it.

Fix

[!warning] Close OBS first OBS rewrites the scene collection JSON when it exits. Any edit made while OBS is running will be overwritten. Confirm with tasklist.exe | grep obs64 (WSL) or Task Manager.

1. Make the missing script reachable

Either:

  • Re-extract / restore the script to a path under the new profile (recommended — gives you a clean canonical home), or
  • Leave it in the rescue/migration folder and point OBS there (fragile if the rescue folder is later deleted).

2. Back up the scene collection JSON

SCENES="/mnt/c/Users/<current-windows-user>/AppData/Roaming/obs-studio/basic/scenes"
STAMP="$(date +%Y%m%d-%H%M%S)"
cp -p "$SCENES/<Collection>.json" "$SCENES/<Collection>.json.$STAMP.bak"

3. Rewrite the paths atomically

Edit the JSON in place by parsing it, replacing the matched path strings, and writing through a temp file (so a crash mid-write can't corrupt the collection):

python3 <<'PY'
import json, os
scenes  = "/mnt/c/Users/<current-windows-user>/AppData/Roaming/obs-studio/basic/scenes"
mapping = {
    "C:/Users/<old>/Pictures/.../<script>.lua":
    "C:/Users/<new>/Pictures/.../<script>.lua",
}
for fn in ("<Collection>.json",):
    path = os.path.join(scenes, fn)
    d = json.load(open(path))
    for entry in d.get("modules", {}).get("scripts-tool", []):
        if entry.get("path") in mapping:
            entry["path"] = mapping[entry["path"]]
    tmp = path + ".tmp"
    json.dump(d, open(tmp, "w"), indent=4)
    os.replace(tmp, path)
PY

OBS scene JSONs use forward slashes in Windows paths — preserve that style.

4. Verify

Re-run the diagnostic Python snippet and confirm every printed path resolves to a real file (translate C://mnt/c/ from WSL).

5. Reopen OBS

Load the scene collection. The popup should be gone.

Why not just remove the script?

If the script is part of a third-party overlay pack (Twitch Pimpage, OWN3D, etc.), removing the registration also removes the overlay's source presets — fixing the path keeps the imported scenes intact. If you don't actually use the overlay anymore, removing the scripts-tool entry is fine; OBS will silently drop the broken reference on next save.

Generalization

This same pattern applies to any OBS asset path stored in a scene collection or profile:

  • Browser source local files
  • Image / media source files
  • Lua / Python script paths
  • VST plugin paths

All of them are absolute, all of them survive a Windows profile rename in stale form, and all of them can be batch-rewritten with the same JSON-edit pattern above. Search for the old username substring across %APPDATA%\obs-studio\ to catch them all in one pass.