vxcontrol/pentagi · error
failed to unmarshal search arguments: %w
Error message
failed to unmarshal search arguments: %w
What it means
The graphiti_search tool receives its arguments as a raw JSON byte slice from the LLM and unmarshals them into GraphitiSearchAction. If the payload is not valid JSON for that struct (malformed JSON, wrong types such as a string where an integer array is expected, or a truncated payload), the handler logs the error and returns "failed to unmarshal search arguments: %w". The tool never executes against partially parsed arguments.
Source
Thrown at backend/pkg/tools/graphiti_search.go:160
func (t *graphitiSearchTool) IsAvailable() bool {
return t.graphitiClient != nil && t.graphitiClient.IsEnabled()
}
// Handle executes the search based on search_type
func (t *graphitiSearchTool) Handle(ctx context.Context, name string, args json.RawMessage) (string, error) {
if !t.IsAvailable() {
return "Graphiti knowledge graph is not enabled. No historical context or memory data is available for this search.", nil
}
logger := logrus.WithContext(ctx).WithFields(enrichLogrusFields(t.flowID, t.taskID, t.subtaskID, logrus.Fields{
"tool": name,
"args": string(args),
}))
var searchArgs GraphitiSearchAction
if err := json.Unmarshal(args, &searchArgs); err != nil {
logger.WithError(err).Error("failed to unmarshal search arguments")
return "", fmt.Errorf("failed to unmarshal search arguments: %w", err)
}
searchArgs.Query = strings.TrimSpace(searchArgs.Query)
if searchArgs.Query == "" {
logger.Error("query parameter is required")
return "", fmt.Errorf("query parameter is required")
}
if searchArgs.SearchType == "" {
logger.Error("search_type parameter is required")
return "", fmt.Errorf("search_type parameter is required")
}
ctx, observation := obs.Observer.NewObservation(ctx)
retrieverTitle, ok := graphitiRetrieverTitles[searchArgs.SearchType.String()]
if !ok {
retrieverTitle = "retrieve context from graphiti knowledge graph"View on GitHub (pinned to ea665308ba)
Solutions
- Inspect the wrapped json.Unmarshal cause and the logged raw "args" payload to find the exact syntax/type mistake.
- Re-issue the tool call as a proper JSON object matching GraphitiSearchAction (search_type, query, message as strings; max_results, max_depth, min_mentions as numbers; node_labels, edge_types as arrays).
- If the provider double-encodes arguments (a quoted JSON string), fix the client/adapter so arguments are passed as an object, not a string.
- Ensure search_type uses one of the enum values (temporal_window, entity_relationships, diverse_results, episode_context, successful_tools, recent_context, entity_by_label).
Example fix
// before (invalid: numbers as strings, array as string)
{"search_type": "entity_by_label", "query": "find hosts", "max_results": "5", "node_labels": "Host"}
// after
{"search_type": "entity_by_label", "query": "find hosts", "max_results": 5, "node_labels": ["Host"]} Defensive patterns
Strategy: validation
Validate before calling
func validGraphitiArgs(raw string) error {
var probe map[string]any
if err := json.Unmarshal([]byte(raw), &probe); err != nil {
return err // not valid JSON at all
}
for _, intField := range []string{"max_results", "max_depth", "min_mentions"} {
if v, ok := probe[intField]; ok {
if _, isNum := v.(float64); !isNum {
return fmt.Errorf("%s must be a number", intField)
}
}
}
for _, arrField := range []string{"node_labels", "edge_types"} {
if v, ok := probe[arrField]; ok {
if _, isArr := v.([]any); !isArr {
return fmt.Errorf("%s must be an array", arrField)
}
}
}
return nil
} Type guard
func isGraphitiSearchAction(v any) (*GraphitiSearchAction, bool) {
a, ok := v.(GraphitiSearchAction)
return &a, ok
} Try / catch
if _, err := graphitiSearchHandle(ctx, args); err != nil {
if strings.HasPrefix(err.Error(), "failed to unmarshal search arguments:") {
// log raw args, fix JSON syntax/types, re-issue the tool call
}
} Prevention
- Emit tool arguments as a single JSON object — never a JSON-encoded string inside a string.
- Use numeric literals for max_results/max_depth/min_mentions and arrays for node_labels/edge_types.
- Test providers with a strict structured-output/JSON mode before production use.
- Log the raw args (the handler already does) and diff against the schema when debugging.
When it happens
Trigger: The model emits graphiti_search arguments that are not valid JSON: unquoted keys, trailing commas, single quotes, a JSON-encoded string instead of an object (double-encoded), max_results/max_depth/min_mentions given as strings ("5" instead of 5), or node_labels/edge_types given as a string instead of an array.
Common situations: Weak LLM providers that emit sloppy JSON; prompt frameworks that double-serialize arguments; a provider streaming a truncated tool-call payload; custom OpenAI-compatible endpoints that mangle tool_call.function.arguments.
Understand the failure class
Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.
Related errors
- failed to unmarshal %s search guide action arguments: %w
- failed to unmarshal %s store guide action arguments: %w
- invalid subtask patch: %w
- failed to switch provider: %w
- failed to set provider: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/5c49814da7ec29ff.
Report an issue: GitHub.