# Troubleshooting

> Find the fix for a common problem when you install, build or run MentorAgent: startup errors, blocked requests, roles, confirmation and local models.

- URL: https://docs.mentoragent.net/get-started/troubleshooting
- Verified with: MentorAgent 1.0.0
- Last updated: 2026-10-14
- Packages: Novior.MentorAgent, Novior.MentorAgent.Server

Use this page when something does not work while you install, build or run MentorAgent. Each section starts from what you see, then gives the cause and the fix.

Find your symptom in this list:

- **Install and build:** [the build cannot find a type of your model provider](https://docs.mentoragent.net/get-started/troubleshooting#the-build-cannot-find-a-type-of-your-model-provider), [the app still runs the old packages](https://docs.mentoragent.net/get-started/troubleshooting#the-application-still-runs-the-old-mentoragent-packages), [the Azure OpenAI Responses client throws MissingMethodException](https://docs.mentoragent.net/get-started/troubleshooting#the-azure-openai-responses-client-throws-missingmethodexception).
- **Startup:** [the app stops with an InvalidOperationException](https://docs.mentoragent.net/get-started/troubleshooting#the-app-stops-at-startup-with-an-invalidoperationexception), [the app cannot map the Model Context Protocol (MCP) or Agent-to-Agent (A2A) endpoint](https://docs.mentoragent.net/get-started/troubleshooting#the-app-stops-at-startup-cannot-map-the-mcp-or-a2a-endpoint).
- **Clients and connections:** [the widget button does nothing](https://docs.mentoragent.net/get-started/troubleshooting#the-widget-button-does-nothing), [a browser client is blocked by Cross-Origin Resource Sharing (CORS)](https://docs.mentoragent.net/get-started/troubleshooting#a-browser-client-is-blocked-by-cors), [every request to /mcp answers 500](https://docs.mentoragent.net/get-started/troubleshooting#every-request-to-mcp-answers-500), [a client cannot connect to the hub](https://docs.mentoragent.net/get-started/troubleshooting#a-webassembly-or-javascript-client-cannot-connect-to-the-hub), [a confirmation answer gets a 404](https://docs.mentoragent.net/get-started/troubleshooting#the-answer-to-a-confirmation-gets-a-404), [restoring a conversation fails](https://docs.mentoragent.net/get-started/troubleshooting#restoring-a-conversation-answers-400-or-415).
- **What the agent does:** [it does not call your method](https://docs.mentoragent.net/get-started/troubleshooting#the-agent-does-not-call-your-method), [an action with RequiredRoles is always refused](https://docs.mentoragent.net/get-started/troubleshooting#an-action-with-requiredroles-is-always-refused), [an action runs without a confirmation box](https://docs.mentoragent.net/get-started/troubleshooting#an-action-that-changes-data-runs-without-a-confirmation-box), [an action that only reads asks for confirmation](https://docs.mentoragent.net/get-started/troubleshooting#an-action-asks-for-confirmation-but-it-only-reads), [a local model ignores the instructions](https://docs.mentoragent.net/get-started/troubleshooting#a-local-model-ignores-the-instructions-or-times-out).
- **Known issues:** [the defects of this version, in What's new](https://docs.mentoragent.net/whats-new#known-issues).

## The build cannot find a type of your model provider

The build stops with `error CS0246`: the type or namespace `OpenAI`, `AzureOpenAIClient` or `DefaultAzureCredential` could not be found.

**Cause.** MentorAgent brings no SDK of a model provider. You add the package of your provider, at the version you choose.

**Fix.** Add the package that your code needs:

| Your code uses | Add the package |
|---|---|
| `OpenAIClient`, or `AsIChatClient()` on an OpenAI client | `Microsoft.Extensions.AI.OpenAI`, which brings `OpenAI` |
| `AzureOpenAIClient` | `Azure.AI.OpenAI` and `Microsoft.Extensions.AI.OpenAI` |
| `DefaultAzureCredential` | `Azure.Identity` |
| `AIProjectClient` | `Microsoft.Agents.AI.Foundry` |
| `AnthropicClient` | `Microsoft.Agents.AI.Anthropic` |

With the Responses API of Azure OpenAI, pin the version: see [The Azure OpenAI Responses client throws MissingMethodException](https://docs.mentoragent.net/get-started/troubleshooting#the-azure-openai-responses-client-throws-missingmethodexception). If your code uses an Agent Framework hosting package that earlier versions of MentorAgent installed, such as `Microsoft.Agents.AI.Hosting.A2A.AspNetCore`, add that package to your project yourself.

## The application still runs the old MentorAgent packages

After the upgrade to 1.0.0, the build succeeds, but the application still behaves like 1.0.0-rc.15.

**Cause.** A project still references a package with the old ID, which ends with 1.0.0-rc.15. The old and the new packages build side by side without an error, and `using` lines with the old namespaces keep reaching the old package.

**Fix.** Follow [Move to the Novior.MentorAgent packages](https://docs.mentoragent.net/whats-new#move-to-the-noviormentoragent-packages). In every project, `dotnet list package --include-transitive` must list only `Novior.MentorAgent` packages.

## The widget button does nothing

**Cause.** The widget is on a page or layout that renders statically. It shows its button, but nothing handles the click.

**Fix.** Make the whole app interactive, with `<Routes @rendermode="InteractiveServer" />` in `Components/App.razor`. Or run the widget on the server: give it its own `InteractiveServer` render mode in the layout. [Place the widget](https://docs.mentoragent.net/get-started/existing-app#place-the-widget) shows both.

## The app stops at startup with an InvalidOperationException

The app ends before it listens, with an `InvalidOperationException`. On a Blazor Server app or a worker, the terminal shows "Hosting failed to start" and the reason. Some hosts stop earlier, at the `Map…` call, with the same message. This happens when the host maps the endpoints of `Novior.MentorAgent.Server`: the hub and its HTTP endpoints, the Model Context Protocol (MCP) server, or the Agent-to-Agent (A2A) agent.

| The message starts with | Fix |
|---|---|
| `[MentorAgent] AppName is required.` | Set `options.AppName` |
| `[MentorAgent] Configure ChatClient or Agent.` | Set `options.ChatClient`, or `options.Agent` for your own `AIAgent` |
| `[MentorAgent] Set ChatClient OR Agent, not both.` | Keep only one of them |
| `[MentorAgent] ScanAssemblies cannot be empty.` | List your assemblies, for example `options.ScanAssemblies = [typeof(Program).Assembly]` |
| `[MentorAgent] Both ChatHistoryProvider and ChatHistoryProviderFactory are set.` | Set only one of them. Prefer `ChatHistoryProviderFactory` when the app has more than one user |
| `OpenAI:Key is missing` | The key is not in the configuration: see below |

In the [Quickstart](https://docs.mentoragent.net/get-started/quickstart), the key is in user secrets. In the project folder, run `dotnet user-secrets list`: it must show `OpenAI:Key`. If it does not, run `dotnet user-secrets set OpenAI:Key <your-key>` again. The app reads user secrets only in the Development environment. On a server, supply the key another way: see [Keys and configuration](https://docs.mentoragent.net/configure/production#keys-and-configuration) in the Production checklist.

A .NET MAUI app has no host start to check the options, so the same messages appear the first time MentorAgent is used.

## The app stops at startup: Cannot map the MCP or A2A endpoint

`app.MapMentorAgentMcp()` or `app.MapMentorAgentA2A()` stops the app when the server is off or not registered. The message says which. A call to `AddMentorAgentMcp()` or `AddMentorAgentA2A()` in the wrong place also stops the app. It stops at the map call or, if the app maps no endpoint, when the host starts.

| The message starts with | Cause | Fix |
|---|---|---|
| `[MentorAgent] Cannot map MCP endpoint: McpServerEnabled is false.` | The option is off. The A2A message names `A2AServerEnabled`. | Set `options.McpServerEnabled = true` (or `options.A2AServerEnabled = true`) in the `AddMentorAgent` callback, or remove the call. |
| `[MentorAgent] Cannot map the MCP endpoint: the MCP server is not registered.` | The option is on, but nothing registered the server. The A2A message starts `[MentorAgent] Cannot map the A2A endpoint: the A2A server is not registered.` | Call `builder.Services.AddMentorAgentMcp()` (or `AddMentorAgentA2A()`) after `AddMentorAgent()`. `AddMentorAgentServer()` calls both. |
| `[MentorAgent] McpServerEnabled is true, but AddMentorAgentMcp() ran before AddMentorAgent()` | The add method came first, found no options and registered nothing. The A2A message names `A2AServerEnabled` and `AddMentorAgentA2A()`. | Move the call after `AddMentorAgent()`. |
| `[MentorAgent] McpServerEnabled is true, but it was false when AddMentorAgent() read it` | The option was turned on after `AddMentorAgent()` read it: in a `Configure` or `PostConfigure` of `MentorOptions`, or in configuration bound later. | Set the option in the `AddMentorAgent` callback. |

- `AddMentorAgentMcp()`, `AddMentorAgentA2A()` and the `MapMentorAgent…` methods are in the `Novior.MentorAgent.Server` package. A Blazor Server app that serves MCP or A2A without the hub must add that package. If the compiler says that `WebApplication` has no `MapMentorAgentMcp`, the project does not reference the package.
- `AddMentorAgentMcp()` called before `AddMentorAgent()` registers nothing, because it reads the options that `AddMentorAgent` stores. The app then stops and says so.

[MCP server](https://docs.mentoragent.net/configure/mcp-server#minimal-configuration) and [A2A server](https://docs.mentoragent.net/configure/a2a-server#minimal-configuration) show how to turn each one on.

## A browser client is blocked by CORS

The browser console reports a Cross-Origin Resource Sharing (CORS) error for the request to `/mcp`. Desktop and IDE clients connect without a problem.

**Cause.** The `/mcp` endpoint has no CORS policy. Only browsers check for one, so only a browser-based client is blocked.

**Fix.** Opt in to a policy. Define a policy named `MentorAgentMcp` that lists your origins and exposes the `Mcp-Session-Id` header. You can register it before or after `AddMentorAgent`:

```csharp title="Program.cs"
services.AddCors(options => options.AddPolicy("MentorAgentMcp",
    policy => policy.WithOrigins("https://tools.example.com")
        .AllowAnyHeader()
        .AllowAnyMethod()
        .WithExposedHeaders("Mcp-Session-Id")));
```

Then call `app.UseCors()` and require the policy on the endpoint:

```csharp title="Program.cs"
app.UseCors();
app.MapMentorAgentMcp(configure: endpoint => endpoint.RequireCors("MentorAgentMcp"));
```

If you register no policy with that name, MentorAgent registers one that allows any origin. In production, list your own origins. [MCP server](https://docs.mentoragent.net/configure/mcp-server#complete-configuration) has the complete configuration. With authentication, [Secure the endpoints](https://docs.mentoragent.net/configure/secure-endpoints#complete-configuration) shows the order of the calls.

## Every request to /mcp answers 500

**Cause.** You required a CORS policy on the endpoint, but the app has no CORS middleware. ASP.NET Core refuses to run such an endpoint. The log says that a middleware that supports CORS was not found. A plain `MapMentorAgentMcp()` does not need the middleware.

**Fix.** Call `app.UseCors()` before you map the endpoint, as in [A browser client is blocked by CORS](https://docs.mentoragent.net/get-started/troubleshooting#a-browser-client-is-blocked-by-cors). If no browser calls `/mcp`, remove the `RequireCors` call instead.

## A WebAssembly or JavaScript client cannot connect to the hub

**Cause.** The client runs on a different origin from the server, for example another port during development, and the browser blocks the SignalR handshake. You do not need CORS when the client is served by the same host.

**Fix.**

1. On the server, add a CORS policy that lists every client origin and allows credentials.
2. Call `UseCors` before `UseAuthentication()` and `UseAuthorization()`, and write those two calls in `Program.cs` yourself. If you leave them out, ASP.NET Core adds them before CORS. Then authorization can refuse the browser's preflight request. This is a request that the browser sends before the real request, and it carries no credentials.
3. On the client, use the absolute URL of the hub.

[Secure the endpoints](https://docs.mentoragent.net/configure/secure-endpoints#complete-configuration) and [Blazor WebAssembly and Auto](https://docs.mentoragent.net/configure/blazor-webassembly#complete-configuration) show the code.

## The answer to a confirmation gets a 404

Your own client answers a confirmation with `POST /mentor/approve`, and the server replies `404`.

**Cause.** No turn waits for the answer any more. The question was answered already, the user pressed Stop, or the connection that raised it has closed. Closing a connection ends its turn.

**Fix.** Nothing is wrong. Treat `404` as "nothing left to answer" and close the dialog. `200` means that the waiting turn received the answer. The WebAssembly client of `Novior.MentorAgent.Blazor` already does this. A `401` or `403` has another cause: the request does not carry the identity of the hub connection. See [Secure the endpoints](https://docs.mentoragent.net/configure/secure-endpoints).

## Restoring a conversation answers 400 or 415

`POST /mentor/session` restores a conversation from a snapshot that `GET /mentor/session` returned. When it refuses the snapshot, the live conversation stays as it is. The body of the answer says why.

| What you see | Cause and fix |
|---|---|
| `415` | The request is not JSON. Send the snapshot with the content type `application/json`. |
| `400`: the snapshot is from an earlier version | Save the conversation again with `GET /mentor/session`. |
| `400`: the snapshot was edited or belongs to another user | The snapshot was edited, or it was saved for another user. Send back exactly what `GET /mentor/session` returned, for the same user. |
| `400`: the Data Protection keys are gone | The ASP.NET Core Data Protection keys that protected the snapshot are gone. Persist and share the ASP.NET Core Data Protection key ring, as the next paragraph explains, and save the conversation again. |
| `400`: the snapshot comes from a host that stores the history differently | The snapshot comes from a host that keeps the conversation history in another way. For example, one host keeps it on the model service with [`UseServiceManagedHistory`](https://docs.mentoragent.net/reference/options#useservicemanagedhistory), and the other keeps it in your application. Restore a snapshot only on a host that is set up in the same way. |
| `404` right after you connect | The server has not registered the connection yet. Restore after the first hub call, or try once more. |

To restore after a restart, or on another instance, persist and share the ASP.NET Core [Data Protection key ring](https://learn.microsoft.com/aspnet/core/security/data-protection/configuration/overview), as you do for authentication cookies. Windows and Azure App Service keep the keys by default. A container without a volume does not.

Without sign-in, the owner check of the snapshot sees every visitor as the same anonymous user, so a snapshot opens for any connection of the application.

## The agent does not call your method

Check these in order:

1. **The service is registered** in dependency injection (DI). If it is not, the log has a warning that the tool was not found in DI, and the method is left out.
2. **Its assembly is in `ScanAssemblies`.**
3. **The method is public, not static, and declared on the class itself.** Inherited methods are ignored. This rule also applies to the classes listed in the `Tools` of a team member.
4. **The method has `[MentorAction]`, or `[Description]` with a text.** A `[Description]` with an empty text is ignored.
5. **The description says what the method is for.** The model chooses tools by their name and description, so a vague description is a likely reason for a missed call.
6. **Tool filtering did not send the action.** With [`EnableToolFiltering`](https://docs.mentoragent.net/reference/options#enabletoolfiltering) on, the model receives only the actions that match the message. Write each description in the words your users use. The Debug log lists the actions that were sent on each turn.
   - An action that needs confirmation is sent only when its description scores above [`ToolFilterMinScore`](https://docs.mentoragent.net/reference/options#toolfilterminscore).
   - A short answer to a question from the agent, such as "yes, go ahead", carries the actions of the previous message.
7. **The action asks for confirmation, and the caller cannot confirm.** The MCP server and the A2A agent card do not publish an action that asks for confirmation. Tool filtering does not send such an action when a message matches nothing. A `[MentorAction]` asks for confirmation by default, unless it declares `ReadOnly = true` or `RequiresConfirmation = false`. See [`RequireConfirmationForWrites`](https://docs.mentoragent.net/reference/options#requireconfirmationforwrites).
   - If it only reads, declare `ReadOnly = true`.
   - If it must run without asking, declare `RequiresConfirmation = false`.
8. **A team member lists the class in `Tools`.** The class is the toolbox of that member only. The coordinator does not call its methods, and the MCP server and the A2A card do not publish them. A line in the log, at Information level, names each such class.
   - Put an action that the coordinator must also offer on a class that no member lists.
   - A `[MentorSkill]` class keeps its coordinator tools.

## An action with RequiredRoles is always refused

Check these causes, one by one:

- **Nobody is signed in, or MentorAgent cannot see who is.** Anonymous users are refused. When the app has no authentication at all, every user is refused: the app has neither `Novior.MentorAgent.Server` nor an `AuthenticationStateProvider`.
- **The user does not have the role.** MentorAgent checks roles with `ClaimsPrincipal.IsInRole` (the `ClaimTypes.Role` claims, by default). With ASP.NET Core Identity, roles reach the claims only when role support is registered: the Blazor template's `AddIdentityCore<ApplicationUser>()` needs `.AddRoles<IdentityRole>()`.
- **The roles are in a `roles` claim, and the identity does not name that claim.** A `roles` claim works once the identity names it as its `RoleClaimType`. Microsoft.Identity.Web does this for you. With JwtBearer and `MapInboundClaims = false`, set `TokenValidationParameters.RoleClaimType = "roles"`. Otherwise `IsInRole` looks for `ClaimTypes.Role`, and every action with `RequiredRoles` stays refused.
- **The app is a .NET MAUI Blazor Hybrid app.** There is no ASP.NET Core user, so actions with `RequiredRoles` are refused for everyone until you supply one: see [.NET MAUI (Blazor Hybrid)](https://docs.mentoragent.net/configure/maui#complete-configuration).
- **Your own `AuthenticationStateProvider` adds the roles.** On the hub, on `/mentor/chat` and over A2A, MentorAgent reads the user from the request. It does not ask your `AuthenticationStateProvider` there, so a claim that only it adds is not seen. Add the claim with an `IClaimsTransformation`. ASP.NET Core applies it to `HttpContext.User`, and so to the user of the hub connection.
- **The caller is an MCP client or another agent.** An MCP client sees an action with `RequiredRoles` only when [`McpCallerPrincipal`](https://docs.mentoragent.net/reference/options#mcpcallerprincipal) returns an authenticated user who holds the role. Other channels withhold gated actions too: see [Where nobody can answer](https://docs.mentoragent.net/concepts/governance#where-nobody-can-answer).

## An action that changes data runs without a confirmation box

**Cause.** A `[MentorAction]` that is not read-only asks for confirmation by default, unless it declares `RequiresConfirmation = false`. A method that changes data runs without asking in these cases:

- it declares `RequiresConfirmation = false`;
- it declares `ReadOnly = true`, or `IsReadOnlyAction` returns `true` for its tool name;
- it is a method with `[Description]` alone: [`RequireConfirmationForWrites`](https://docs.mentoragent.net/reference/options#requireconfirmationforwrites) covers `[MentorAction]` methods only;
- `RequireConfirmationForWrites` or [`RequireConfirmation`](https://docs.mentoragent.net/reference/options#requireconfirmation) is `false`;
- with `HitlMode.Native`, a rule of [`AutoApprovalRules`](https://docs.mentoragent.net/reference/options#autoapprovalrules) approves it.

**Fix.** Remove the declaration that opts out, or mark the method `[MentorAction]`. For a method that you cannot annotate, use the [`RequiresApproval`](https://docs.mentoragent.net/reference/options#requiresapproval) predicate.

MentorAgent also writes a warning to the log the first time it reads your actions. The warning lists the writes that run without confirmation: the `[MentorAction]` methods that opted out, and the methods with only `[Description]` that are not declared read-only. See [`RequireConfirmationForWrites`](https://docs.mentoragent.net/reference/options#requireconfirmationforwrites).

With [tool filtering](https://docs.mentoragent.net/reference/options#enabletoolfiltering) on, an action without confirmation can reach the model on any message: see [Tool filtering and confirmation](https://docs.mentoragent.net/concepts/governance#tool-filtering-and-confirmation).

## An action asks for confirmation, but it only reads

**Cause.** A `[MentorAction]` that declares neither `ReadOnly = true` nor `RequiresConfirmation` is treated as an action that changes data. It asks for confirmation, and the MCP server and the A2A card do not publish it.

**Fix.**

- Declare `ReadOnly = true` on an action that only reads, or list its tool name in [`IsReadOnlyAction`](https://docs.mentoragent.net/reference/options#isreadonlyaction).
- Declare `RequiresConfirmation = false` on a write that must run without asking.
- To turn the default off for the whole application, set [`RequireConfirmationForWrites`](https://docs.mentoragent.net/reference/options#requireconfirmationforwrites) to `false`. An action then asks only when it declares `RequiresConfirmation = true`.

> **Caution:**
> Declare `ReadOnly` only on an action that only reads: some MCP clients skip their own confirmation for such a tool.

## The Azure OpenAI Responses client throws MissingMethodException

The app builds without a warning. When your code calls `GetResponsesClient()` on an `AzureOpenAIClient`, it throws:

```text
System.MissingMethodException: Method not found: 'Void OpenAI.Responses.ResponsesClient..ctor(System.ClientModel.Primitives.ClientPipeline, OpenAI.OpenAIClientOptions)'.
```

**Cause.** `Azure.AI.OpenAI` 2.9.0-beta.1 calls a constructor that `OpenAI` 2.11 removed. A package that needs `OpenAI` 2.11 or later brings the newer version: for example a newer `Microsoft.Extensions.AI.OpenAI`, `Microsoft.Agents.AI.OpenAI` or `Microsoft.Agents.AI.Foundry`.

**Fix.** Keep `OpenAI` at 2.10. Give each of these references one exact version, built on `OpenAI` 2.10:

```xml
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="[10.6.0]" />
<PackageReference Include="Microsoft.Agents.AI.Foundry" Version="[1.17.0-preview.260804.1]" />
```

Keep the second line only if you use `AIProjectClient` or `FoundryEvals`. The Chat Completions client (`GetChatClient`), OpenAI direct, and Ollama through its OpenAI-compatible endpoint need no pin. Remove the pin when `Azure.AI.OpenAI` ships a version built on a newer `OpenAI`.

## A local model ignores the instructions or times out

**Cause: the context window is too short.** The context window is the amount of text that the model reads at once. The default window of an Ollama model is shorter than the prompt that MentorAgent builds. Ollama then cuts the start of the prompt, without an error. The model answers without your instructions or tools.

**Fix.** Create a variant of the model with a larger context, with a `Modelfile` and `ollama create`, and use the variant's name as the model name. [Ollama and other local models](https://docs.mentoragent.net/configure/model-providers#ollama-and-other-local-models) shows the file and the command.

**Cause.** The model is slow. On a CPU, a long prompt can take minutes.

**Fix.**

- Raise `NetworkTimeout` in the `OpenAIClientOptions` of the client.
- If you turned on `EnableSafetyCheck`, `RequireLookupForRecordQuestions` or `RequireActionForChangeRequests`, raise `SafetyCheckTimeout` too. These options make an extra model call on each message. This call is the *classifier*, and `SafetyCheckTimeout` limits it.
- If the classifier call of `RequireLookupForRecordQuestions` or `RequireActionForChangeRequests` times out, the turn runs without that option.
- To make the classifiers faster, point them at a faster model with [`ClassifierChatClient`](https://docs.mentoragent.net/reference/options#classifierchatclient).

[Model providers](https://docs.mentoragent.net/configure/model-providers#ollama-and-other-local-models) has the complete Ollama setup.

**Also check** that the model supports tool calling. MentorAgent needs it to call your methods.

## Known issues

1.0.0 has four known issues. Their causes and workarounds are in [Known issues](https://docs.mentoragent.net/whats-new#known-issues) in What's new.

---

- Previous: [Samples](https://docs.mentoragent.net/samples.md)
- Next: [The three agent levels](https://docs.mentoragent.net/concepts/agent-levels.md)
