Skip to content

A falsy throw from the model makes sendMessage reject instead of reporting an error step #7485

Description

@aglinxinyuan

What happened?

TexeraAgent.sendMessage is written to never reject: every failure is turned into an error step and returned as { error } on the resolved AgentMessageResult. One path breaks that contract.

The catch block reads .name off the caught value without guarding it:

// texera-agent.ts:659-660
} catch (error: any) {
  const isAborted = error.name === "AbortError" || this.abortController?.signal.aborted;

If the value thrown is null or undefined, that line throws a TypeError inside the catch, so it propagates out and sendMessage rejects instead of resolving. Callers that only handle the documented resolved shape get an unhandled rejection, and the turn leaves no error step behind — the failure is invisible in the ReAct history.

Confirmed against main:

TypeError: null is not an object (evaluating 'error.name')

with the returned value undefined (the promise rejected rather than resolving).

The same line is the only place in the method that dereferences the caught value before it has been normalized; every other use goes through error instanceof Error ? error.message : String(error), which already handles this correctly.

How to reproduce?

Drive the agent with a model that throws a falsy value:

const model = new MockLanguageModelV4({
  doGenerate: async () => {
    throw null;
  },
});
const agent = new TexeraAgent({ model, modelType: "m", agentId: "a", systemPrompt: "s" });

await agent.sendMessage("hi");
// rejects with TypeError: null is not an object (evaluating 'error.name')
// expected: resolves with { error: "null", stopped: false }

MockLanguageModelV4 comes from the ai/test export, so this needs no network.

Version/Branch

1.3.0-incubating-SNAPSHOT (main)

Expected behavior

The catch should normalize before inspecting, e.g.

const isAborted = (error as any)?.name === "AbortError" || this.abortController?.signal.aborted;

so that a falsy throw takes the ordinary error-step path and sendMessage keeps its promise never to reject.

Additional context

Found while raising texera-agent.ts coverage from 51% to 99.8%. A provider throwing null is uncommon, so the practical impact is low — but the cost of the fix is one optional-chain, and the current behaviour is the single exception to an otherwise total contract.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions