tinyhumansai/openhuman · error

agentTeamApi.get: teamId is required

Error message

agentTeamApi.get: teamId is required

What it means

Guard inside agentTeamApi.get: the team id argument is checked for truthiness before issuing the openhuman.agent_team_get RPC. An empty/whitespace-free falsy id means the caller has no team reference and the request would be meaningless, so it throws immediately.

Source

Thrown at app/src/services/api/agentTeamApi.ts:199

   */
  list: async (params: AgentTeamListParams = {}): Promise<AgentTeam[]> => {
    assertPositiveInt(params.limit, 'limit');
    log('list params=%o', params);
    const response = await callCoreRpc<{ teams?: AgentTeam[]; count?: number }>({
      method: 'openhuman.agent_team_list',
      params,
    });
    const teams = response.teams ?? [];
    log('list received teams=%d count=%o', teams.length, response.count);
    return teams;
  },

  /**
   * Fetch one team plus its members and tasks. Returns `null` when the id is
   * unknown (the controller answers `{ team: null }`).
   */
  get: async (teamId: string): Promise<TeamView | null> => {
    if (!teamId) throw new Error('agentTeamApi.get: teamId is required');
    log('get teamId=%s', teamId);
    const response = await callCoreRpc<{ team: TeamView | null }>({
      method: 'openhuman.agent_team_get',
      params: { teamId },
    });
    log('get found=%o', response.team != null);
    return response.team ?? null;
  },

  /**
   * List a team's teammate messages in sequence order. Unwraps the
   * `{ messages }` envelope and narrows each run-event payload to a typed
   * {@link TeamMessagePayload}.
   */
  listMessages: async (teamId: string, limit?: number): Promise<TeamMessage[]> => {
    if (!teamId) throw new Error('agentTeamApi.listMessages: teamId is required');
    assertPositiveInt(limit, 'limit');
    log('listMessages teamId=%s limit=%o', teamId, limit);

View on GitHub (pinned to a221052e0d)

Solutions

  1. Only call get() once a team id exists — gate the effect/handler on the id being non-empty
  2. Default the selector to skip the fetch: if (!teamId) return null instead of calling the API
  3. Fix the upstream state so the empty id never reaches this layer

Example fix

// before
useEffect(() => { agentTeamApi.get(selectedTeamId).then(setTeam); }, [selectedTeamId]);

// after
useEffect(() => {
  if (!selectedTeamId) { setTeam(null); return; }
  agentTeamApi.get(selectedTeamId).then(setTeam).catch(notify);
}, [selectedTeamId]);
Defensive patterns

Strategy: validation

Validate before calling

const hasTeamId = (id: string | null | undefined): id is string => typeof id === 'string' && id.length > 0;
if (!hasTeamId(teamId)) { setTeam(null); } else { agentTeamApi.get(teamId).then(setTeam); }

Type guard

const isNonEmptyString = (v: unknown): v is string => typeof v === 'string' && v.length > 0;

Try / catch

try { const team = await agentTeamApi.get(teamId); }
catch (e) { if (String(e.message).includes('teamId is required')) showEmptyState(); else throw e; }

Prevention

When it happens

Trigger: Calling agentTeamApi.get(''), agentTeamApi.get(undefined as any), or get(id) where id came from an unset route param / unselected list item. Only a non-empty string reaches callCoreRpc.

Common situations: A detail panel rendered before a team is selected in the list; a route like /teams/:teamId mounted with no id; a store field still null on first render feeding get() directly.

Related errors


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