{"record":{"id":"4cf35a8977adb7ab","repo":"warpdotdev/warp","slug":"settings-symlink-rejected","errorCode":"settings_symlink_rejected","errorMessage":"settings_symlink_rejected","messagePattern":"settings_symlink_rejected","errorType":"exception","errorClass":"InspectionError","httpStatus":null,"severity":"error","filePath":"resources/bundled/skills/tui-migrate-setup/scripts/inspect_shared_settings.py","lineNumber":125,"sourceCode":"    for line in contents.splitlines(keepends=True):\n        is_header, header_path = _table_header_path(line)\n        if is_header:\n            current_section = header_path\n        if current_section in relevant_sections:\n            selected.append(line)\n\n    return \"\".join(selected)\n\n\ndef _read_toml_object(\n    path: Path,\n    paths: list[tuple[str, ...]],\n    *,\n    missing_ok: bool,\n    role: str,\n) -> dict[str, Any]:\n    if path.is_symlink():\n        raise InspectionError(\"settings_symlink_rejected\")\n    if missing_ok and not path.exists():\n        return {}\n    try:\n        contents = path.read_text(encoding=\"utf-8\")\n        selected = _select_relevant_toml(contents, paths)\n        value = tomllib.loads(selected) if selected else {}\n    except (OSError, tomllib.TOMLDecodeError) as error:\n        raise InspectionError(f\"{role}_settings_unavailable_or_invalid\") from error\n    if not isinstance(value, dict):\n        raise InspectionError(f\"{role}_settings_unavailable_or_invalid\")\n    return value\n\n\ndef inspect_settings(\n    schema: dict[str, Any],\n    source: dict[str, Any],\n    destination: dict[str, Any],\n) -> dict[str, Any]:","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/warpdotdev/warp/blob/e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc/resources/bundled/skills/tui-migrate-setup/scripts/inspect_shared_settings.py#L107-L143","documentation":"_read_toml_object() refuses to follow symlinks: if the --source (GUI) or --destination (TUI) settings TOML is a symlink, it raises settings_symlink_rejected before reading a byte. This is deliberate — following a link could read or write outside the managed settings area, and the script's sanitized errors must not depend on where a link points.","triggerScenarios":"Settings file managed by a dotfiles manager (stow, chezmoi, an install Makefile) that symlinks the settings TOML into place; a manual ln -s to a shared config across machines.","commonSituations":"Developers with dotfiles repos; shared configs across machines via symlink; fresh clones where the manager symlinked instead of materializing real files.","solutions":["Replace the symlink with a real file: cp -L link tmp && mv tmp link-path, then re-run","Point the argument directly at the real file the symlink resolves to","Reconfigure the dotfiles manager to template/copy this settings file instead of symlinking it"],"exampleFix":"# before\n~/.warp/settings.toml -> ~/dotfiles/warp/settings.toml  (symlink)\npython inspect_shared_settings.py --source ~/.warp/settings.toml ...\n# error: settings_symlink_rejected\n\n# after\ncp -L ~/.warp/settings.toml /tmp/settings.toml && mv /tmp/settings.toml ~/.warp/settings.toml\npython inspect_shared_settings.py --source ~/.warp/settings.toml ...","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\nfor label, p in (('source', Path(args.source)), ('destination', Path(args.destination))):\n    if p.is_symlink():\n        raise SystemExit(f'{label} settings file {p} is a symlink; materialize it first')","typeGuard":null,"tryCatchPattern":"if result.returncode != 0 and 'settings_symlink_rejected' in result.stderr:\n    # resolve with readlink -f, or cp -L to materialize, then re-run the inspection\n    ...","preventionTips":["Configure dotfiles managers to copy/template settings files, not symlink","Pre-check is_symlink on both settings paths before migration","Keep the settings file real and store the source of truth in the repo instead"],"tags":["filesystem","symlink","security","settings"],"backgroundTag":null,"analyzedSha":"e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc","analyzedAt":"2026-08-16T08:27:25.381Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}