{"record":{"id":"7f19134e7e8a701f","repo":"vxcontrol/pentagi","slug":"failed-to-unmarshal-s-store-answer-action-argumen","errorCode":null,"errorMessage":"failed to unmarshal %s store answer action arguments: %w","messagePattern":"failed to unmarshal (.+?) store answer action arguments: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/tools/search.go","lineNumber":218,"sourceCode":"\t\t\t\tctx,\n\t\t\t\tagentCtx.ParentAgentType,\n\t\t\t\tagentCtx.CurrentAgentType,\n\t\t\t\tfiltersData,\n\t\t\t\tqueriesText,\n\t\t\t\tdatabase.VecstoreActionTypeRetrieve,\n\t\t\t\tbuffer.String(),\n\t\t\t\ts.taskID,\n\t\t\t\ts.subtaskID,\n\t\t\t)\n\t\t}\n\n\t\treturn buffer.String(), nil\n\n\tcase StoreAnswerToolName:\n\t\tvar action StoreAnswerAction\n\t\tif err := json.Unmarshal(args, &action); err != nil {\n\t\t\tlogger.WithError(err).Error(\"failed to unmarshal search answer action arguments\")\n\t\t\treturn \"\", fmt.Errorf(\"failed to unmarshal %s store answer action arguments: %w\", name, err)\n\t\t}\n\n\t\t// Anonymize before anything else so all downstream paths (including error\n\t\t// branches that emit langfuse events) only ever expose the anonymized form.\n\t\tvar (\n\t\t\tanonymizedAnswer   = s.replacer.ReplaceString(action.Answer)\n\t\t\tanonymizedQuestion = s.replacer.ReplaceString(action.Question)\n\t\t)\n\n\t\teventMetadata := map[string]any{\n\t\t\t\"tool_name\":   name,\n\t\t\t\"message\":     action.Message,\n\t\t\t\"doc_type\":    searchVectorStoreDefaultType,\n\t\t\t\"answer_type\": action.Type,\n\t\t}\n\t\topts := []langfuse.EventOption{\n\t\t\tlangfuse.WithEventName(\"store search answer to vector store\"),\n\t\t\tlangfuse.WithEventInput(action.Question),","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/tools/search.go#L200-L236","documentation":"The `store answer` tool received arguments that failed to decode into `StoreAnswerAction` (expected at least `question` and `answer` string fields). The decode error is wrapped with the tool name so callers can identify which tool call was malformed.","triggerScenarios":"Agent calls the `store answer` tool and `json.Unmarshal(args, &StoreAnswerAction{})` fails — missing `answer` field, `question` sent as a non-string, or the model returned prose instead of a JSON object.","commonSituations":"Model omitting the required `answer` key; long answers causing providers to truncate the tool-call JSON; weaker/local models ignoring the tool schema; schema renamed fields (e.g. `text` → `answer`) while prompts still teach the old names.","solutions":["Inspect the wrapped `%w` error and the raw args log to find the missing/misspelled field.","Ensure the tool schema advertised to the LLM lists `question` and `answer` as required strings.","Enable the provider's structured/JSON output mode for tool calls.","Retry the agent step; the model usually corrects malformed arguments on a second attempt."],"exampleFix":"// before\nargs := []byte(`{\"question\":\"q\"}`) // missing required answer\n// after\nargs, _ := json.Marshal(StoreAnswerAction{Question: \"q\", Answer: \"a\"})","handlingStrategy":"validation","validationCode":"var probe struct {\n    Question string `json:\"question\"`\n    Answer   string `json:\"answer\"`\n}\nif err := json.Unmarshal(args, &probe); err != nil {\n    return fmt.Errorf(\"invalid store answer args: %w\", err)\n}\nif strings.TrimSpace(probe.Question) == \"\" || strings.TrimSpace(probe.Answer) == \"\" {\n    return errors.New(\"question and answer must be non-empty strings\")\n}","typeGuard":"func isValidStoreAnswerArgs(args []byte) bool {\n    var a search.StoreAnswerAction\n    return json.Unmarshal(args, &a) == nil && a.Question != \"\" && a.Answer != \"\"\n}","tryCatchPattern":"out, err := searchTool.Handle(ctx, tools.StoreAnswerToolName, args)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to unmarshal\") {\n        logger.Warnf(\"store answer args rejected: %v; raw=%s\", err, string(args))\n        return askModelToReemitToolCall(ctx)\n    }\n    return err\n}","preventionTips":["Mark question/answer as required strings in the tool schema.","Watch for providers truncating long tool-call JSON; cap answer length in the prompt.","Log raw args with the error to identify missing fields quickly.","Use structured output mode so the model cannot emit prose instead of JSON."],"tags":["json","unmarshal","llm-tool-call","search"],"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"}