unclecode/crawl4ai · error · AttributeError

{self.__class__.__name__} object has no attribute '{attr}'

Error message

{self.__class__.__name__} object has no attribute '{attr}'

What it means

CrawlResultContainer wraps a list of CrawlResult objects (used by arun_many and by the markdown backward-compat layer) and delegates unknown attribute access to its first element. When the container is empty, there is nothing to delegate to, so __getattr__ raises AttributeError naming the container class and the missing attribute.

Source

Thrown at crawl4ai/models.py:315:5504

        if isinstance(results, list):
            self._results = results
        else:
            self._results = [results]

    def __iter__(self):
        return iter(self._results)

    def __getitem__(self, index):
        return self._results[index]

    def __len__(self):
        return len(self._results)

    def __getattr__(self, attr):
        # Delegate attribute access to the first element.
        if self._results:
            return getattr(self._results[0], attr)
        raise AttributeError(f"{self.__class__.__name__} object has no attribute '{attr}'")

    def __repr__(self):
        return f"{self.__class__.__name__}({self._results!r})"

RunManyReturn = Union[
    CrawlResultContainer[CrawlResultT],
    AsyncGenerator[CrawlResultT, None]
]


# END of backward compatibility code for markdown/markdown_v2.
# When removing this code in the future, make sure to:
# 1. Replace the private attribute and property with a standard field
# 2. Update any serialization logic that might depend on the current behavior

class AsyncCrawlResponse(BaseModel):
    html: str
    response_headers: Dict[str, str]

View on GitHub (pinned to 7e80152142)

Solutions

  1. Treat the return of arun_many as a collection: check len(result) or iterate for r in result before accessing fields
  2. Log and inspect why zero results were produced (bad URLs, all crawls failed, empty input list)
  3. If you expected a single result, use crawler.arun(url) instead of arun_many, or index results[0] after checking length

Example fix

// before
print(result.markdown)  # AttributeError when container is empty
// after
results = await crawler.arun_many(urls, config=config)
for r in results:
    print(r.url, r.markdown.raw_markdown)
Defensive patterns

Strategy: validation

Validate before calling

results = await crawler.arun_many(urls, config=run_config)
if len(results) == 0:
    logger.warning("no crawl results produced; check input URLs and crawl errors")
    return []
first = results[0]

Type guard

from crawl4ai import CrawlResultContainer, CrawlResult

def as_result_list(container):
    if isinstance(container, CrawlResultContainer):
        return list(container)
    return [container] if isinstance(container, CrawlResult) else []

Try / catch

try:
    url = results.url
except AttributeError:
    # container had zero results; fall back to iterating/inspecting failures
    for r in results:
        ...  # empty; investigate crawl failures instead
    raise

Prevention

When it happens

Trigger: Calling crawler.arun_many(urls, ...) where every crawl fails or the list is empty, then accessing result.url / result.markdown / any CrawlResult attribute on the container; accessing any attribute on a CrawlResultContainer built with no results.

Common situations: Assuming arun_many returns a single CrawlResult rather than a container; seed URL lists that are empty after dedup/validation; all crawls erroring out but the code proceeding to read attributes; also triggered incidentally when the deprecated-property tombstones (markdown_v2 etc.) are accessed through an empty container.

Related errors


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