unclecode/crawl4ai · error · ValueError

Profile not found: {profile_path}

Error message

Profile not found: {profile_path}

What it means

The module-level shrink_profile(profile_path, level, dry_run) helper validates that profile_path exists and is a directory before shrinking a Chrome profile. A missing path or a file (not dir) raises ValueError('Profile not found: ...'). Note it also understands Chrome's Default/ subdirectory layout and operates on that if present.

Source

Thrown at crawl4ai/browser_profiler.py:104

    dry_run: bool = False
) -> Dict[str, Any]:
    """
    Shrink a Chrome profile to reduce storage while preserving auth data.

    Args:
        profile_path: Path to profile directory
        level: How aggressively to shrink (LIGHT/MEDIUM/AGGRESSIVE/MINIMAL)
        dry_run: If True, only report what would be removed

    Returns:
        Dict with 'removed', 'kept', 'bytes_freed', 'size_before', 'size_after', 'errors'
    """
    if level == ShrinkLevel.NONE:
        return {"removed": [], "kept": [], "bytes_freed": 0, "errors": []}

    profile = Path(profile_path)
    if not profile.exists() or not profile.is_dir():
        raise ValueError(f"Profile not found: {profile_path}")

    # Chrome profiles may have data in Default/ subdirectory
    target = profile / "Default" if (profile / "Default").is_dir() else profile

    keep = KEEP_PATTERNS[level]
    result = {"removed": [], "kept": [], "bytes_freed": 0, "errors": [], "size_before": _get_size(profile)}

    for item in target.iterdir():
        name = item.name
        # Check if item matches any keep pattern
        if any(name == p or name.startswith(p) for p in keep):
            result["kept"].append(name)
        else:
            size = _get_size(item)
            if not dry_run:
                try:
                    shutil.rmtree(item) if item.is_dir() else item.unlink()
                    result["removed"].append(name)

View on GitHub (pinned to 7e80152142)

Solutions

  1. Verify the path first: Path(p).is_dir() before calling.
  2. Pass the actual profile directory (the one containing Default/ or the profile files), absolute if possible.
  3. If you only have a profile name, use BrowserProfiler().shrink_profile(name) which joins profiles_dir for you.

Example fix

# before
shrink_profile('my-profile', ShrinkLevel.MEDIUM)  # relative name -> not a dir

# after
profiler = BrowserProfiler()
result = profiler.shrink_profile('my-profile', ShrinkLevel.MEDIUM)  # resolves under profiles_dir
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
p = Path(profile_path).expanduser().resolve()
if not p.is_dir():
    raise ValueError(f'profile directory missing: {p}')

Type guard

from pathlib import Path
def is_profile_dir(path) -> bool:
    p = Path(path).expanduser()
    return p.is_dir()

Try / catch

try:
    result = shrink_profile(path, level)
except ValueError as e:
    if 'Profile not found' in str(e):
        logger.warning('skipping missing profile %s', path)
        result = None
    else:
        raise

Prevention

When it happens

Trigger: Calling shrink_profile('/nonexistent/path'); passing a profile name instead of the resolved absolute path to the free function (the BrowserProfiler method resolves names — the free function does not); passing a .zip backup file path; profile was deleted after a previous shrink.

Common situations: Using the functional API directly instead of the class; relative paths resolved against an unexpected cwd; profiles_dir relocated between runs.

Related errors


AI-assisted analysis of unclecode/crawl4ai@7e80152142 (2026-08-14). Data as JSON: /api/errors/bc10773e68e19cb5. Report an issue: GitHub.