tinyhumansai/openhuman · warning · TeamError

unknown member: {member_id}

Error message

unknown member: {member_id}

What it means

Thrown by agent_teams assign_task when an owner_member_id is supplied that matches no member row in that team (checked via list_agent_team_members). It compares against member IDs — the generated row identifiers returned by creation, not the human-readable member names. Passing a member name, an id from another team, or a stale id after membership changes produces this error; the task insert is aborted.

Source

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

    owner_member_id: Option<&str>,
    depends_on: &[String],
) -> Result<AgentTeamTask> {
    log::debug!(
        "{LOG_PREFIX} assign_task.entry team={team_id} deps={}",
        depends_on.len()
    );

    let team = run_ledger::get_agent_team(&config.workspace_dir, team_id)?
        .ok_or_else(|| anyhow!("unknown team: {team_id}"))?;
    let _ = team;

    let existing = run_ledger::list_agent_team_tasks(&config.workspace_dir, team_id)?;
    let task_id = format!("task-{}", Uuid::new_v4().simple());

    if let Some(owner) = owner_member_id {
        let members = run_ledger::list_agent_team_members(&config.workspace_dir, team_id)?;
        if !members.iter().any(|m| m.id == owner) {
            return Err(anyhow!(TeamError::UnknownMember {
                member_id: owner.to_string(),
            }));
        }
    }

    validate_dependencies(&task_id, depends_on, &existing)?;

    let order_index = existing.len() as i64;
    let task = run_ledger::upsert_agent_team_task(
        &config.workspace_dir,
        AgentTeamTaskUpsert {
            id: task_id.clone(),
            team_id: team_id.to_string(),
            title: title.to_string(),
            objective: objective.map(str::to_string),
            status: AgentTeamTaskStatus::Todo,
            owner_member_id: owner_member_id.map(str::to_string),
            depends_on: depends_on.to_vec(),

View on GitHub (pinned to a221052e0d)

Solutions

  1. Fetch the team via agent_team_get and read each member's id field; use that exact id as owner_member_id
  2. Omit owner_member_id to create an unassigned task and let members claim it
  3. Regenerate any stored member ids after re-creating a team

Example fix

// before
{"team_id":"team-3f9a...","owner_member_id":"researcher",...} // -> unknown member: researcher
// after: agent_team_get shows member id "m-8c21..."
{"team_id":"team-3f9a...","owner_member_id":"m-8c21...",...}
Defensive patterns

Strategy: validation

Validate before calling

// Resolve owner to a real member id before assigning:
let view = tool_exec("agent_team_get", json!({"team_id": tid})).await?;
let owner_id = view.members.iter().find(|m| m.name == owner_name)
    .ok_or_else(|| anyhow!("no member named {owner_name}"))?.id.clone();
tool_exec("agent_team_assign_task", json!({"team_id": tid, "owner_member_id": owner_id, /* ... */})).await

Type guard

fn member_id_in_team(view: &TeamView, member_id: &str) -> bool {
    view.members.iter().any(|m| m.id == member_id)
}

Try / catch

match tool_exec("agent_team_assign_task", args).await {
    Err(e) if e.to_string().contains("unknown member") => {
        let view = tool_exec("agent_team_get", json!({"team_id": args["team_id"]})).await?;
        // map name->id from view.members and re-submit, or drop owner_member_id (unassigned task)
        unimplemented!()
    }
    other => other,
}

Prevention

When it happens

Trigger: Setting owner_member_id to the member's name ('researcher') instead of its id ('m-...'); mixing ids across teams; a member removed/re-created so the old id no longer resolves.

Common situations: LLM filling owner from the roster it wrote in the prompt (names) rather than the create response (ids); maintaining task templates that hard-code old member ids.

Related errors


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