dagger/dagger · error
object %q function %q is marked @agent but does not return L
Error message
object %q function %q is marked @agent but does not return LLM!; @agent functions must have the agent(base: LLM!): LLM! shape
What it means
An @agent function must have the exact shape agent(base: LLM!): LLM! — it is invoked by a compose fold that supplies an LLM base and expects a new LLM back. validateAgentFunction rejects any @agent function whose return type is not the core LLM object (core/module.go:243), failing module load.
Source
Thrown at core/module.go:243
}
for _, argRes := range fn.Args {
arg := argRes.Self()
if argRequired(arg) {
return fmt.Errorf("object %q function %q is marked @generate but declares required argument %q; @generate functions must be callable with no arguments",
obj.OriginalName, fn.OriginalName, arg.OriginalName)
}
}
return nil
}
// validateAgentFunction enforces the @agent middleware contract (hack/designs/workspace-agents.md
// §3): the function must return LLM! and must declare exactly one required
// argument, an LLM! (the base the compose fold supplies, whatever it is
// named). A non-LLM! return, a missing base, or any other required argument is
// a hard error at module load.
func validateAgentFunction(obj *ObjectTypeDef, fn *Function) error {
if !returnsCoreObject(fn, "LLM") {
return fmt.Errorf("object %q function %q is marked @agent but does not return LLM!; @agent functions must have the agent(base: LLM!): LLM! shape",
obj.OriginalName, fn.OriginalName)
}
baseExempted := false
for _, argRes := range fn.Args {
arg := argRes.Self()
if !argRequired(arg) {
continue
}
if !baseExempted && isCoreLLMArg(arg) {
baseExempted = true
continue
}
return fmt.Errorf("object %q function %q is marked @agent but declares required argument %q; an @agent function may only require a single LLM! argument (the base the compose fold supplies)",
obj.OriginalName, fn.OriginalName, arg.OriginalName)
}
if !baseExempted {
return fmt.Errorf("object %q function %q is marked @agent but does not declare a required LLM! argument; @agent functions must have the agent(base: LLM!): LLM! shape (the base the compose fold supplies)",
obj.OriginalName, fn.OriginalName)View on GitHub (pinned to 82ba2681db)
Solutions
- Change the return type to the core LLM! type and return the composed LLM
- Return the base LLM with the prompt/step applied (e.g. base.withPrompt(...))
- Remove the @agent pragma if the function is not part of an agent compose fold
Example fix
// before
@agent()
answer(base: LLM): string { return base.query("..."); }
// after
@agent()
answer(base: LLM): LLM { return base.withPrompt("..."); } Defensive patterns
Strategy: validation
Validate before calling
if (fn.pragmas.includes("agent") && !(fn.returnType === "LLM" && fn.returnNonNull)) {
throw new Error(`@agent ${fn.name} must return LLM!, got ${fn.returnType}`);
} Type guard
const returnsLLM = (fn) => fn.returnType === "LLM" && fn.returnNonNull === true;
Prevention
- Use the exact agent(base: LLM!): LLM! shape
- Return base.withPrompt(...)/composed LLM, not extracted values
- Validate module schema after adding @agent
When it happens
Trigger: Decorating a function with @agent that returns String, Void, a custom object, or nullable LLM instead of core LLM!.
Common situations: Authoring an agent step that returns a final answer string instead of the composed LLM; adapting an ordinary helper into an @agent function without adjusting its signature.
Related errors
- object %q function %q is marked @agent but declares required
- object %q function %q is marked @agent but does not declare
- function requires the current conversation; invoke it as an
- object %q function %q is marked @up but declares required ar
- object %q function %q is marked @generate but returns %s; @g
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/0cb261f932cb4232.
Report an issue: GitHub.