{"record":{"id":"94393518564ec748","repo":"langchain-ai/deepagents","slug":"invalid-glob-pattern-pattern-r-exc","errorCode":null,"errorMessage":"Invalid glob pattern {pattern!r}: {exc}","messagePattern":"Invalid glob pattern (.+?): (.+?)","errorType":"validation","errorClass":"InvalidGlobPatternError","httpStatus":null,"severity":"error","filePath":"libs/deepagents/deepagents/backends/utils.py","lineNumber":165,"sourceCode":"\n    flags = wcglob.BRACE | wcglob.GLOBSTAR\n    # A leading `/` anchors to the search root: strip it so it matches against\n    # the (slash-less) relative path, but decide anchoring from the original\n    # pattern so `/*.py` stays root-anchored instead of collapsing to a\n    # basename-at-any-depth match.\n    anchored = \"/\" in pattern\n    try:\n        compiled = wcglob.compile(pattern.lstrip(\"/\"), flags=flags)\n    except Exception as exc:\n        # `wcmatch` only raises private types (`wcmatch._wcparse.PatternLimitException`),\n        # so catch broadly and re-raise a public type: every backend can then catch\n        # one public type instead of importing from a private module. Log first --\n        # the breadth also swallows genuine bugs (a non-`str` pattern, a wcmatch\n        # version bump), which would otherwise reach the user as \"invalid pattern\"\n        # for a pattern that is perfectly valid.\n        logger.warning(\"wcmatch refused glob pattern %r (%s): %s\", pattern, type(exc).__name__, exc)\n        msg = f\"Invalid glob pattern {pattern!r}: {exc}\"\n        raise InvalidGlobPatternError(msg) from exc\n\n    if anchored:\n\n        def matcher(rel_path: str) -> bool:\n            return bool(compiled.match(rel_path))\n    else:\n\n        def matcher(rel_path: str) -> bool:\n            return bool(compiled.match(PurePosixPath(rel_path).name))\n\n    return matcher\n\n\ndef _normalize_content(file_data: FileData) -> str:\n    \"\"\"Normalize current and legacy file data content to a plain string.\n\n    Args:\n        file_data: `FileData` dict with `content` key.","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/deepagents/deepagents/backends/utils.py#L147-L183","documentation":"When the `wcmatch` library refuses to compile a glob pattern, `compile_grep_include_glob` logs a warning (because wcmatch's breadth can also reject valid patterns) and re-raises as `InvalidGlobPatternError` with the underlying exception text chained. This catches truly malformed patterns, non-str inputs, and wcmatch version behavioral changes.","triggerScenarios":"Passing syntactically invalid globs (e.g. unmatched brackets `[abc`, bad brace nesting `{a,b`) to `glob`/`grep` include or exclude parameters; passing None or a non-string where a pattern string is expected; upgrading wcmatch so a previously accepted pattern is refused.","commonSituations":"LLM- or user-supplied glob strings; hand-written patterns with unbalanced wildcards; dependency version bumps changing glob grammar strictness.","solutions":["Fix the glob syntax (balance `[...]` and `{...}`, escape literal `[`/`]`)","Ensure the pattern is a plain str before passing it","Test the pattern against wcmatch directly to see the precise refusal reason in the chained exception","Pin/upgrade the wcmatch version if a previously valid pattern regressed"],"exampleFix":"// before\nbackend.glob('src/[a-*.py')  # unmatched bracket\n// after\nbackend.glob('src/[a-z]*.py')","handlingStrategy":"try-catch","validationCode":"def check_glob(pattern):\n    if not isinstance(pattern, str):\n        raise TypeError('glob pattern must be a string')\n    for open_c, close_c in (('[', ']'), ('{', '}')):\n        if pattern.count(open_c) != pattern.count(close_c):\n            raise ValueError(f'unbalanced {open_c}{close_c} in glob: {pattern!r}')\n    return pattern","typeGuard":"def is_valid_glob_shape(pattern: object) -> bool:\n    if not isinstance(pattern, str) or not pattern:\n        return False\n    return (\n        pattern.count('[') == pattern.count(']')\n        and pattern.count('{') == pattern.count('}')\n    )","tryCatchPattern":"from deepagents.backends.utils import InvalidGlobPatternError\nimport logging\ntry:\n    files = backend.glob(pattern)\nexcept InvalidGlobPatternError as exc:\n    logging.warning('bad glob %r: %s', pattern, exc)\n    files = []","preventionTips":["Validate bracket/brace balance before passing patterns from users or LLMs","Coerce patterns to str explicitly","Watch for wcmatch upgrades changing grammar; test critical patterns in CI","Check the chained exception (`from exc`) for the precise wcmatch refusal reason"],"tags":["glob","validation","pattern"],"backgroundTag":"invalid-glob-pattern","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}