vxcontrol/pentagi · error

failed to unmarshal search guide action arguments

Error message

failed to unmarshal %s search guide action arguments: %w

What it means

The search_guide tool received LLM-generated arguments that could not be parsed as JSON into SearchGuideAction. The agent's function-calling output did not match the tool's JSON schema, so the guide.Handle dispatcher aborts before running the vector store search.

Solutions

  1. Log the raw args string (already captured in logrus field 'args') and inspect exactly what the model produced.
  2. Re-generate the flow / retry the agent turn — often a single malformed sample from the model.
  3. Check that the tool JSON schema advertised to the LLM matches SearchGuideAction fields (type, message, questions) and their requiredness.
  4. If a specific provider consistently fails, tighten its function-calling mode or switch to a provider with strict JSON output.
  5. If the model can't produce valid JSON reliably, add pre-parse cleanup (strip code fences) before json.Unmarshal.

Example fix

// before: unmarshal raw args directly
if err := json.Unmarshal(args, &action); err != nil { ... }

// after: defensively strip a common LLM artifact (markdown fences)
cleaned := bytes.Trim(bytes.TrimSpace(args), "` \n")
cleaned = bytes.TrimPrefix(bytes.TrimPrefix(cleaned, []byte("json")), []byte("\n"))
if err := json.Unmarshal(cleaned, &action); err != nil {
    return "", fmt.Errorf("failed to unmarshal %s search guide action arguments: %w", name, err)
}
Defensive patterns

Strategy: validation

Validate before calling

func isValidSearchGuideArgs(args json.RawMessage) bool {
    var probe struct {
        Type      string   `json:"type"`
        Questions []string `json:"questions"`
    }
    return json.Unmarshal(args, &probe) == nil && probe.Type != ""
}

Type guard

func asSearchGuideAction(args json.RawMessage) (*SearchGuideAction, bool) {
    var a SearchGuideAction
    if err := json.Unmarshal(args, &a); err != nil || a.Type == "" {
        return nil, false
    }
    return &a, true
}

Try / catch

res, err := tool.Handle(ctx, "search_guide", args)
if err != nil {
    var jsonErr *json.UnmarshalTypeError
    if errors.As(err, &jsonErr) {
        log.Printf("invalid tool args (field %s): %v", jsonErr.Field, err)
        return retryWithCorrectedSchema()
    }
    return err
}

Prevention

When it happens

Trigger: Agent model emits malformed JSON for the search_guide tool call (e.g. unquoted strings, trailing commas, wrong field names/types like guide_type as a number), or args contains text/prose instead of a JSON object.

Common situations: Weaker LLMs or providers with relaxed function-calling emitting invalid JSON; prompt templates changed so the schema example no longer matches; a provider returning tool args wrapped in markdown fences; version drift between tool schema in provider prompts and the Go struct.

Related errors


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

Appendix: source

Thrown at backend/pkg/tools/guide.go:91

	}

	ctx, observation := obs.Observer.NewObservation(ctx)
	logger := logrus.WithContext(ctx).WithFields(enrichLogrusFields(g.flowID, g.taskID, g.subtaskID, logrus.Fields{
		"tool": name,
		"args": string(args),
	}))

	if g.store == nil {
		logger.Error("pgvector store is not initialized")
		return "", fmt.Errorf("pgvector store is not initialized")
	}

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

		filters := map[string]any{
			"doc_type":   guideVectorStoreDefaultType,
			"guide_type": action.Type,
		}

		metadata := langfuse.Metadata{
			"tool_name":     name,
			"message":       action.Message,
			"limit":         guideVectorStoreResultLimit,
			"threshold":     guideVectorStoreThreshold,
			"doc_type":      guideVectorStoreDefaultType,
			"guide_type":    action.Type,
			"queries_count": len(action.Questions),
		}

		retriever := observation.Retriever(

View on GitHub (pinned to ea665308ba)