FutureSearch Logofuturesearch
  • Solutions
  • Pricing
  • Research
  • Docs
  • Evals
  • Blog
  • Company
  • Try it for free
FutureSearch Logo

General inquiry? You can reach us at hello@futuresearch.ai.

Company

Team & CareersPressPrivacy PolicyTerms of Service

Developers

SDK DocsAPI ReferenceCase StudiesGitHubSupport

Integrations

Claude CodeCursorChatGPT CodexClaude.ai

Follow Us

X (Twitter)@dschwarz26LinkedIn
FutureSearchdocs
Your research team
Installation
  • All install methods
  • Claude.ai
  • Claude Code
  • Web App
  • Python SDK
  • Skill
Reference
  • API Key
  • classify
  • dedupe
  • forecast
  • merge
  • rank
  • agent_map
  • MCP Server
  • Progress Monitoring
  • Chaining Operations
Guides
  • LLM-Powered Data Labeling
  • Add a Column via Web Research
  • Classify and Label Rows
  • Deduplicate Training Data
  • Error Handling
  • Filter a Dataset Intelligently
  • Find Profitable Prediction Market Trades
  • Forecast Outcomes for a List of Entities
  • Value a Private Company
  • Join Tables Without Shared Keys
  • Rank Data by External Metrics
  • Resolve Duplicate Entities
  • Scale Deduplication to 20K Rows
  • Turn Claude into an Accurate Forecaster
Case Studies
  • Deduplicate Contact Lists
  • Deduplicate CRM Records
  • Enrich Contacts with Company Data
  • Forecast a Sum-of-the-Parts SpaceX IPO Valuation
  • Forecast Anthropic and OpenAI IPO Valuations
  • Forecast Founder Seed Valuations for AI Researchers
  • Forecast When Anthropic and OpenAI Will IPO
  • Fuzzy Match Across Tables
  • Link Records Across Medical Datasets
  • LLM Cost vs. Accuracy
  • Merge Costs and Speed
  • Merge Thousands of Records
  • Multi-Stage Lead Qualification
  • Research and Rank Web Data
  • Run 10,000 LLM Web Research Agents
  • Score Cold Leads via Web Research
  • Score Leads from Fragmented Data
  • Screen 10,000 Rows
  • Screen Job Listings
  • Screen Stocks by Economic Sensitivity
  • Screen Stocks by Investment Thesis
FutureSearchby futuresearch
by futuresearch

Error Handling

FutureSearch operations process rows independently. When some rows fail (e.g. due to content policy violations), the rest still complete. This page explains how failures are reported and how to access partial results.

Row-Level vs Task-Level Failure

Every row in a FutureSearch operation is processed by its own agent. Failures are isolated to individual rows:

  • Row succeeds: _status = "completed", result columns populated
  • Row fails: _status = "failed", _error column contains the reason

A task's overall status depends on how many rows succeeded:

OutcomeTask Statuserror field
All rows succeedcompletednull
Some rows failfailed"N/M rows failed"
All rows failfailed"N/M rows failed"

Even when a task's status is failed, partial results are available for all rows that succeeded.

Content Policy Violations

The most common row-level failure is a content policy violation. This happens when the LLM provider refuses to process a particular input — typically because the row content triggers a safety filter.

When this occurs, the affected row's _error column will contain:

Content policy violation: the model refused to process this input.

Content policy violations are not retried, since the model will consistently refuse the same input.

Python SDK

The SDK returns results even when some rows fail. The error field on the result indicates whether there were failures:

result = await task.await_result(on_progress=print_progress)

if result.error:
    print(f"Warning: {result.error}")  # e.g. "3/50 rows failed"

# Data is always available — includes both succeeded and failed rows
df = result.data
succeeded = df[df["_status"] == "completed"]
failed = df[df["_status"] == "failed"]

# Inspect why rows failed
print(failed[["_error"]].value_counts())

If all rows fail and no data is available, the SDK raises EveryrowError.

Progress Monitoring

The print_progress callback shows failures as they happen:

 5/10  50% |  5 running
 7/10  70% |  3 running | 1 failed
10/10 100% | 2 failed

MCP Tools

When using FutureSearch via MCP (Claude.ai, Claude Code, etc.), the progress tool reports failures inline:

Running: 7/10 complete, 3 running, 1 failed (45s elapsed)

When the task finishes with partial failures, the progress tool directs you to fetch results:

Task failed: 2/10 rows failed
8/10 rows completed successfully — results are available.
Call futuresearch_results(task_id='...', page_size=10) to load the available results.
Failed rows have _status='failed' and _error columns explaining the reason (e.g. content policy violation).

Results are always fetchable, even for failed tasks.

API

The GET /tasks/{task_id}/result endpoint returns data for both completed and failed tasks. Pagination (via offset/limit) works in both cases.

The response includes:

{
  "task_id": "...",
  "status": "failed",
  "artifact_id": "...",
  "error": "2/10 rows failed",
  "data": [
    {"name": "Example A", "answer": "...", "_status": "completed", "_error": null},
    {"name": "Example B", "answer": null, "_status": "failed", "_error": "Content policy violation: the model refused to process this input."}
  ]
}

Working with Partial Results

Filtering to Successful Rows

import pandas as pd

df = result.data
clean = df[df["_status"] == "completed"].drop(columns=["_status", "_error"])

Retrying Failed Rows

Extract the failed rows and re-run the operation on just those:

failed_rows = df[df["_status"] == "failed"].drop(columns=["_status", "_error"])

# Re-run with a different model or rephrased task
retry_result = await session.agent(
    task="...",
    input_data=failed_rows,
    response_schema=schema,
    model="claude-sonnet-4-5-20250514",  # try a different model
)

Chaining After Partial Failures

You can pass the artifact from a partially-failed task to subsequent operations. Only the successfully-completed rows will be processed in the next step:

# First operation — some rows may fail
result = await session.classify(task="...", input_data=df)

# Chain using the artifact — only completed rows carry forward
ranked = await session.rank(
    task="...",
    artifact_id=result.artifact_id,
)