tinyhumansai/openhuman · error · TeamError

task {task_id} cannot depend on itself

Error message

task {task_id} cannot depend on itself

What it means

Thrown by agent_teams::ops::validate_dependencies (reached via assign_task) when a new task's depends_on list contains the new task's own id. Self-dependency is rejected before any ledger write; it wraps TeamError::SelfDependency.

Source

Thrown at src/openhuman/agent/orchestration/agent_teams/ops.rs:404

    })
}

/// Validate a new task's dependency edges against the team's existing tasks.
///
/// Rejects self-dependency, unknown dependency ids, and any edge that would
/// introduce a cycle. The cycle check builds the full graph (existing tasks +
/// the new task with its proposed deps) and runs Kahn's algorithm — the same
/// shape used for workflow phase graphs in `workflow_runs::ops::has_cycle`.
fn validate_dependencies(
    new_task_id: &str,
    depends_on: &[String],
    existing: &[AgentTeamTask],
) -> Result<()> {
    let known: HashSet<&str> = existing.iter().map(|t| t.id.as_str()).collect();

    for dep in depends_on {
        if dep == new_task_id {
            return Err(anyhow!(TeamError::SelfDependency {
                task_id: new_task_id.to_string(),
            }));
        }
        if !known.contains(dep.as_str()) {
            return Err(anyhow!(TeamError::UnknownDependency {
                depends_on: dep.clone(),
            }));
        }
    }

    if has_task_cycle(new_task_id, depends_on, existing) {
        return Err(anyhow!(TeamError::CyclicDependency));
    }

    Ok(())
}

/// Kahn's-algorithm cycle check over the task dependency graph (existing tasks

View on GitHub (pinned to a221052e0d)

Solutions

  1. Filter the new task's own id out of depends_on before submitting
  2. Check the code/template that builds depends_on for an id-variable mix-up
  3. Use distinct, meaningful task ids so deps never collide by construction

Example fix

// before
let depends_on = vec![task_id.clone()]; // self-dep -> error
agent_teams::ops::assign_task(&config, &team_id, &task_id, member_id, &depends_on)?;

// after — strip self-reference before submit
let depends_on: Vec<String> = depends_on.into_iter().filter(|d| d != &task_id).collect();
agent_teams::ops::assign_task(&config, &team_id, &task_id, member_id, &depends_on)?;
Defensive patterns

Strategy: validation

Validate before calling

let depends_on: Vec<String> = depends_on
    .into_iter()
    .filter(|d| d != &new_task_id)
    .collect(); // strip self-reference before assign_task

Type guard

fn has_self_dependency(new_task_id: &str, depends_on: &[String]) -> bool {
    depends_on.iter().any(|d| d == new_task_id)
}

Prevention

When it happens

Trigger: Calling agent_teams assign_task with depends_on containing the very task_id being created — typically a template that interpolates the new id into its own dependency list, or a copy-paste of an existing task's deps onto a task renamed to a dep's id.

Common situations: Generated task graphs where the id and dep id come from the same variable; renaming a task to match one of its dependencies; LLM-authored dependency lists echoing the task id.

Related errors


AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16). Data as JSON: /api/errors/f83a4ce6de8fae40. Report an issue: GitHub.