{"record":{"id":"dc7c9a0add467fc5","repo":"micro/go-micro","slug":"discover-tools-w","errorCode":null,"errorMessage":"discover tools: %w","messagePattern":"discover tools: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agent/agent.go","lineNumber":272,"sourceCode":"func (a *agentImpl) Ask(ctx context.Context, message string) (*Response, error) {\n\treturn a.ask(ctx, message, a.parentRunID)\n}\n\n// Stream sends a message and returns a streaming model response. Tool-calling\n// agent runs still use Ask; Stream is for chat turns where immediate token\n// delivery is more important than tool orchestration.\nfunc (a *agentImpl) Stream(ctx context.Context, message string) (ai.Stream, error) {\n\ta.mu.Lock()\n\tdefer a.mu.Unlock()\n\tif err := ctx.Err(); err != nil {\n\t\treturn nil, err\n\t}\n\tif a.model == nil {\n\t\ta.setup()\n\t}\n\ttoolList, err := a.discoverTools()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"discover tools: %w\", err)\n\t}\n\trunID := uuid.New().String()\n\tctx = ai.WithRunInfo(ctx, ai.RunInfo{\n\t\tRunID:    runID,\n\t\tParentID: a.parentRunID,\n\t\tAgent:    a.opts.Name,\n\t})\n\t// Messages carries the history; Prompt carries the turn being answered.\n\t// Providers build their payload as Messages followed by Prompt, so\n\t// appending the current message here would send it to the model twice.\n\t// Memory has not recorded this turn yet (that happens after the stream\n\t// starts), so the copy is passed through untrimmed: a trailing user\n\t// message equal to this one is real prior context, not a duplicate.\n\tmessages := append([]ai.Message(nil), a.mem.Messages()...)\n\tstream, err := a.model.Stream(ctx, &ai.Request{\n\t\tPrompt:       message,\n\t\tSystemPrompt: a.buildPrompt(),\n\t\tTools:        toolList,","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/agent/agent.go#L254-L290","documentation":"This error wraps any failure from agent.discoverTools() during the Stream path (agent/agent.go:272). discoverTools calls tools.Discover() on the configured tool source to enumerate the tool list for a run; if that discovery fails (registry unreachable, bad service config, backend error), the agent cannot proceed and the underlying error is surfaced with the 'discover tools:' prefix.","triggerScenarios":"Calling Stream (or the run-index commands built on it, e.g. printRunIndex) when a.tools.Discover() returns an error: the tool registry/service is down, a configured service fails to respond, or tool discovery returns a malformed result.","commonSituations":"Misconfigured tool service endpoints in agent Options, the tool registry microservice not running, network/auth failures reaching a remote tool provider, or a version mismatch where the tool service returns an incompatible response.","solutions":["Inspect the wrapped error (%w) to find the underlying discovery failure","Verify the tool registry/service addresses configured via agent Options are reachable (curl/ping the endpoint)","Confirm the tool service is started and registered before calling Stream","Re-check tool service credentials/auth and API version compatibility","Retry after fixing; discovery is attempted per-run so no agent restart is needed"],"exampleFix":"// before\nresp, err := agent.Stream(ctx, msg)\n// ignore wrapped discovery cause\n// after\nresp, err := agent.Stream(ctx, msg)\nif err != nil && strings.Contains(err.Error(), \"discover tools\") {\n    log.Printf(\"tool discovery failed: %v\", errors.Unwrap(err))\n    // check tool service health before retrying\n}","handlingStrategy":"try-catch","validationCode":"// pre-flight: verify the tool source can be discovered\nif h, ok := toolSource.(interface{ HealthCheck(context.Context) error }); ok {\n    if err := h.HealthCheck(ctx); err != nil {\n        return fmt.Errorf(\"tool service not ready: %w\", err)\n    }\n}","typeGuard":"func isDiscoverToolsErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"discover tools:\")\n}","tryCatchPattern":"resp, err := ag.Stream(ctx, msg)\nif err != nil {\n    var base error\n    if strings.HasPrefix(err.Error(), \"discover tools:\") && errors.As(err, &base) {\n        return fmt.Errorf(\"tool discovery failed, check tool service: %w\", base)\n    }\n    return err\n}","preventionTips":["Health-check the tool registry before starting runs","Pin and test tool service endpoints in configuration","Alert on tool service liveness in the same deployment as the agent","Retry transient discovery failures with backoff"],"tags":["go","agent","tool-discovery","error-wrapping"],"backgroundTag":"tool-discovery-failed","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}