{"record":{"id":"8edd226745ce694a","repo":"vxcontrol/pentagi","slug":"failed-to-unmarshal-s-search-in-memory-action-arg","errorCode":null,"errorMessage":"failed to unmarshal %s search in memory action arguments: %w","messagePattern":"failed to unmarshal (.+?) search in memory action arguments: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/memory.go","lineNumber":63,"sourceCode":"\t}\n\n\tctx, observation := obs.Observer.NewObservation(ctx)\n\tlogger := logrus.WithContext(ctx).WithFields(enrichLogrusFields(m.flowID, nil, nil, logrus.Fields{\n\t\t\"tool\": name,\n\t\t\"args\": string(args),\n\t}))\n\n\tif m.store == nil {\n\t\tlogger.Error(\"pgvector store is not initialized\")\n\t\treturn \"\", fmt.Errorf(\"pgvector store is not initialized\")\n\t}\n\n\tswitch name {\n\tcase SearchInMemoryToolName:\n\t\tvar action SearchInMemoryAction\n\t\tif err := json.Unmarshal(args, &action); err != nil {\n\t\t\tlogger.WithError(err).Error(\"failed to unmarshal search in memory action arguments\")\n\t\t\treturn \"\", fmt.Errorf(\"failed to unmarshal %s search in memory action arguments: %w\", name, err)\n\t\t}\n\n\t\tfilters := map[string]any{\n\t\t\t\"flow_id\":  strconv.FormatInt(m.flowID, 10),\n\t\t\t\"doc_type\": memoryVectorStoreDefaultType,\n\t\t}\n\t\tif action.TaskID != nil && *action.TaskID != 0 {\n\t\t\tfilters[\"task_id\"] = action.TaskID.String()\n\t\t}\n\t\tif action.SubtaskID != nil && *action.SubtaskID != 0 {\n\t\t\tfilters[\"subtask_id\"] = action.SubtaskID.String()\n\t\t}\n\n\t\tisSpecificFilters, globalFilters := getGlobalFilters(filters)\n\t\tmetadata := langfuse.Metadata{\n\t\t\t\"tool_name\":        name,\n\t\t\t\"message\":          action.Message,\n\t\t\t\"limit\":            memoryVectorStoreResultLimit,","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/memory.go#L45-L81","documentation":"The `search in memory` tool received tool-call arguments that could not be decoded into the `SearchInMemoryAction` struct. The LLM agent produced JSON that fails `json.Unmarshal` (malformed JSON, wrong types, or unknown/misspelled fields with strict typing). This library wraps the underlying decode error so the caller sees both the tool name and the JSON error.","triggerScenarios":"An agent invokes the `search_in_memory` tool via `memory.Handle(ctx, name, args)` with `name == SearchInMemoryToolName` and `args` bytes that json.Unmarshal cannot decode into `SearchInMemoryAction` — e.g. `questions` sent as a string instead of an array, truncated JSON, or a non-string `query` field.","commonSituations":"LLM providers emitting malformed tool-call JSON; prompt templates that show an outdated action schema; models wrapping arguments in markdown fences or extra nesting; a struct field type changed (e.g. `Questions []string` → string) while the model still emits the old shape.","solutions":["Log and inspect the raw `args` string next to the wrapped error to see exactly what the model produced.","Verify the tool's JSON schema advertised to the LLM matches the current `SearchInMemoryAction` struct fields and types.","Check the inner `%w` error (e.g. `json: cannot unmarshal string into Go struct field ...`) to pinpoint the offending field.","Retry the tool call; if a specific model repeatedly mis-formats arguments, switch provider or strengthen the tool description.","If arguments come from your own code, marshal with `json.Marshal(SearchInMemoryAction{...})` instead of hand-built strings."],"exampleFix":"// before\nargs := []byte(`{\"questions\": \"what is x\"}`) // questions must be an array\n// after\nargs, _ := json.Marshal(SearchInMemoryAction{Questions: []string{\"what is x\"}})","handlingStrategy":"validation","validationCode":"var probe map[string]any\nif err := json.Unmarshal(args, &probe); err != nil {\n    return fmt.Errorf(\"invalid tool args JSON: %w\", err)\n}\nq, ok := probe[\"questions\"].([]any)\nif !ok || len(q) == 0 {\n    return errors.New(\"questions must be a non-empty array of strings\")\n}","typeGuard":"func isValidSearchInMemoryArgs(args []byte) bool {\n    var a struct{ Questions []string `json:\"questions\"` }\n    return json.Unmarshal(args, &a) == nil && len(a.Questions) > 0\n}","tryCatchPattern":"out, err := mem.Handle(ctx, tools.SearchInMemoryToolName, args)\nif err != nil {\n    var jsonErr *json.UnmarshalTypeError\n    if errors.As(err, &jsonErr) {\n        logger.Warnf(\"malformed tool args: %v, raw=%s\", err, string(args))\n        return retryToolCall(ctx) // ask the model to re-emit arguments\n    }\n    return err\n}","preventionTips":["Always advertise the tool JSON schema generated from the Go struct, never a hand-written copy.","Log raw tool arguments on every failure for post-mortem.","Use providers/models with native structured/JSON tool-call output.","Pin the action struct and regenerate the schema whenever fields change."],"tags":["json","unmarshal","llm-tool-call","memory"],"backgroundTag":"json-unmarshal-type-mismatch","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}