vxcontrol/pentagi · error

failed to unmarshal %s store answer action arguments: %w

Error message

failed to unmarshal %s store answer action arguments: %w

What it means

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.

Source

Thrown at backend/pkg/tools/search.go:218

				ctx,
				agentCtx.ParentAgentType,
				agentCtx.CurrentAgentType,
				filtersData,
				queriesText,
				database.VecstoreActionTypeRetrieve,
				buffer.String(),
				s.taskID,
				s.subtaskID,
			)
		}

		return buffer.String(), nil

	case StoreAnswerToolName:
		var action StoreAnswerAction
		if err := json.Unmarshal(args, &action); err != nil {
			logger.WithError(err).Error("failed to unmarshal search answer action arguments")
			return "", fmt.Errorf("failed to unmarshal %s store answer action arguments: %w", name, err)
		}

		// Anonymize before anything else so all downstream paths (including error
		// branches that emit langfuse events) only ever expose the anonymized form.
		var (
			anonymizedAnswer   = s.replacer.ReplaceString(action.Answer)
			anonymizedQuestion = s.replacer.ReplaceString(action.Question)
		)

		eventMetadata := map[string]any{
			"tool_name":   name,
			"message":     action.Message,
			"doc_type":    searchVectorStoreDefaultType,
			"answer_type": action.Type,
		}
		opts := []langfuse.EventOption{
			langfuse.WithEventName("store search answer to vector store"),
			langfuse.WithEventInput(action.Question),

View on GitHub (pinned to ea665308ba)

Solutions

  1. Inspect the wrapped `%w` error and the raw args log to find the missing/misspelled field.
  2. Ensure the tool schema advertised to the LLM lists `question` and `answer` as required strings.
  3. Enable the provider's structured/JSON output mode for tool calls.
  4. Retry the agent step; the model usually corrects malformed arguments on a second attempt.

Example fix

// before
args := []byte(`{"question":"q"}`) // missing required answer
// after
args, _ := json.Marshal(StoreAnswerAction{Question: "q", Answer: "a"})
Defensive patterns

Strategy: validation

Validate before calling

var probe struct {
    Question string `json:"question"`
    Answer   string `json:"answer"`
}
if err := json.Unmarshal(args, &probe); err != nil {
    return fmt.Errorf("invalid store answer args: %w", err)
}
if strings.TrimSpace(probe.Question) == "" || strings.TrimSpace(probe.Answer) == "" {
    return errors.New("question and answer must be non-empty strings")
}

Type guard

func isValidStoreAnswerArgs(args []byte) bool {
    var a search.StoreAnswerAction
    return json.Unmarshal(args, &a) == nil && a.Question != "" && a.Answer != ""
}

Try / catch

out, err := searchTool.Handle(ctx, tools.StoreAnswerToolName, args)
if err != nil {
    if strings.Contains(err.Error(), "failed to unmarshal") {
        logger.Warnf("store answer args rejected: %v; raw=%s", err, string(args))
        return askModelToReemitToolCall(ctx)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01). Data as JSON: /api/errors/7f19134e7e8a701f. Report an issue: GitHub.