From ade3294691c40f3b45456c4760ca2ae811c246f7 Mon Sep 17 00:00:00 2001 From: Stephen Walsh <868017+stphnwlsh@users.noreply.github.com> Date: Sat, 7 Nov 2026 17:41:13 -0600 Subject: [PATCH 1/4] Add a troubleshooting reference page for each template --- src/content/docs/graphql/getting-started.mdx | 2 + .../graphql/reference/troubleshooting.mdx | 94 ++++++++++++++++ src/content/docs/lambda/getting-started.mdx | 2 + .../docs/lambda/reference/troubleshooting.mdx | 86 +++++++++++++++ src/content/docs/mcp/getting-started.mdx | 2 + .../docs/mcp/reference/troubleshooting.mdx | 102 ++++++++++++++++++ .../docs/minimalapi/getting-started.mdx | 2 + .../minimalapi/reference/troubleshooting.mdx | 91 ++++++++++++++++ src/content/docs/webapi/getting-started.mdx | 2 + .../docs/webapi/reference/troubleshooting.mdx | 91 ++++++++++++++++ 10 files changed, 474 insertions(+) create mode 100644 src/content/docs/graphql/reference/troubleshooting.mdx create mode 100644 src/content/docs/lambda/reference/troubleshooting.mdx create mode 100644 src/content/docs/mcp/reference/troubleshooting.mdx create mode 100644 src/content/docs/minimalapi/reference/troubleshooting.mdx create mode 100644 src/content/docs/webapi/reference/troubleshooting.mdx diff --git a/src/content/docs/graphql/getting-started.mdx b/src/content/docs/graphql/getting-started.mdx index 65ad555..22d1ff2 100644 --- a/src/content/docs/graphql/getting-started.mdx +++ b/src/content/docs/graphql/getting-started.mdx @@ -105,6 +105,8 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ +Hit a snag? Check [Troubleshooting](/graphql/reference/troubleshooting/). + ## Where to next diff --git a/src/content/docs/graphql/reference/troubleshooting.mdx b/src/content/docs/graphql/reference/troubleshooting.mdx new file mode 100644 index 0000000..7f818b3 --- /dev/null +++ b/src/content/docs/graphql/reference/troubleshooting.mdx @@ -0,0 +1,94 @@ +--- +title: "Troubleshooting" +description: "Fixes for the common snags when creating, building and running a solution." +sidebar: + order: 5 +--- + +The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Nitro asking you to sign in to a cloud you don't use. + +## Nitro asks you to "Sign in" + +**Symptom:** Opening `https://localhost:7331/graphql` (or `http://localhost:7330/graphql` in Docker) shows a **Sign in** button or prompts you to connect a ChilliCream cloud account. + +Nitro is ChilliCream's GraphQL IDE embedded in Hot Chocolate. Its **Sign in** button is only for syncing workspaces with ChilliCream's cloud service — you don't need an account to browse the schema, write queries or run mutations against your local API. Close or ignore the prompt and run queries straight from the editor. + +## `SchemaMatchesSnapshot` fails after changing a GraphQL type + +**Symptom:** `dotnet test` fails in `tests/Presentation.Tests.Unit/SchemaSnapshotTests.cs` (`SchemaMatchesSnapshot`). + +The unit tests compare the built GraphQL schema against `tests/Presentation.Tests.Unit/Schema.graphql` so accidental breaking changes never slip past review. When you intentionally add or change a query, mutation, type or description, update `tests/Presentation.Tests.Unit/Schema.graphql` to match (see [Add a field](/graphql/guides/add-a-field/)). + +## Port 7330 or 7331 is already in use + +**Symptom:** `dotnet run` stops with `Failed to bind to address https://127.0.0.1:7331: address already in use`, or `docker compose up` fails with `Bind for 0.0.0.0:7330 failed: port is already allocated`. + +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean GraphQL API uses `7330` to `7339` (`7330` HTTP, `7331` HTTPS, `7332` Aspire dashboard, `7333` and `7334` OpenTelemetry Collector). A clash usually means another copy of this template is still running. + +- Check what's running in Docker and stop it: + ```bash + docker compose ps + docker compose down + ``` +- Find a stray host process holding the port (`lsof -i :7330` on macOS and Linux, `netstat -ano | findstr :7330` on Windows) and stop it. +- To move a Docker port, change the left-hand side of its mapping in `docker-compose.yml` (for example `"7335:7330"`) and check the mapped port with: + ```bash + docker compose port api 7330 + ``` +- To move the `dotnet run` ports, edit `applicationUrl` in `src/Presentation/Properties/launchSettings.json`. + +## Browser certificate warning or empty `curl` reply on `dotnet run` + +**Symptom:** Your browser warns that `https://localhost:7331` is untrusted, `curl` fails with `SSL certificate problem: unable to get local issuer certificate`, or calling `http://localhost:7330/graphql` returns `307 Temporary Redirect` with an empty body. + +In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7330` and `https://localhost:7331` and redirects HTTP to HTTPS. + +- Trust the .NET development certificate once on your machine, then restart your browser: + ```bash + dotnet dev-certs https --trust + ``` +- Call `https://localhost:7331/graphql` directly when using `dotnet run`, or pass `-L` to `curl` so it follows the redirect. +- Under `docker compose up -d --build`, the container runs in the `docker` environment and serves plain HTTP on `http://localhost:7330/graphql` with no redirect and no certificate needed. + +## `.NET SDK` version refused by `dotnet new` or `global.json` + +**Symptom:** `dotnet new cleangraphqlapi` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. + +Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). + +- Check which SDKs are installed: + ```bash + dotnet --list-sdks + ``` +- Install the current stable [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). If you only have a preview SDK installed on the machine, either install the stable SDK alongside it or set `"allowPrerelease": true` in `global.json`. + +## `--include-auth` fails with exit code 102 + +**Symptom:** Running `dotnet new cleangraphqlapi --include-auth` stops before writing any files and exits with code `102` (`Invalid option(s)` / missing mandatory option `--authority`). + +When `--include-auth` is switched on, `--authority` is required so a generated solution never starts with a blank JWT issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: + +```bash +dotnet new cleangraphqlapi --name WorksOnMyMachine.Movies \ + --include-auth \ + --authority "https://your-tenant.example.com" \ + --audience "https://api.example.com" +``` + +See [Secure the API](/graphql/guides/secure-the-api/) for sending bearer tokens in Nitro and `curl`. + +## Docker is not running + +**Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. + +Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. + +## `SQLite Error 5: 'database is locked'` + +**Symptom:** Startup migration or a mutation fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. + +`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file — usually a second `dotnet run` terminal or a database viewer. + +- Stop the other process holding `src/Presentation/movie-reviews.db`. +- If you want to wipe the local database and re-seed the sample data from scratch, stop the API, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the API again. +- In Docker Compose, `docker compose down -v` removes the `movie-reviews-data` volume so the next `docker compose up -d` starts with a fresh database. diff --git a/src/content/docs/lambda/getting-started.mdx b/src/content/docs/lambda/getting-started.mdx index 0a91bd5..8a82aa6 100644 --- a/src/content/docs/lambda/getting-started.mdx +++ b/src/content/docs/lambda/getting-started.mdx @@ -93,6 +93,8 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) an +Hit a snag? Check [Troubleshooting](/lambda/reference/troubleshooting/). + ## Where to next diff --git a/src/content/docs/lambda/reference/troubleshooting.mdx b/src/content/docs/lambda/reference/troubleshooting.mdx new file mode 100644 index 0000000..b53ae25 --- /dev/null +++ b/src/content/docs/lambda/reference/troubleshooting.mdx @@ -0,0 +1,86 @@ +--- +title: Troubleshooting +description: Fixes for the common snags when creating, building and invoking a solution locally. +sidebar: + order: 5 +--- + +The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, calling the Lambda emulator like an ordinary web server, or Docker taking a nap. + +## Calling `http://localhost:7350` returns `404` or hangs + +**Symptom:** Sending a `GET` request to `http://localhost:7350/` or `http://localhost:7350/movies` returns `404 page not found`, or calling `https://localhost:7350` fails with an SSL error. + +The container runs the [AWS Lambda Runtime Interface Emulator](https://github.com/aws/aws-lambda-runtime-interface-emulator) over plain HTTP, not an HTTP web server at `/` and not HTTPS. Every local invocation must `POST` a JSON payload to the emulator's invocation endpoint: + +```bash +curl -X POST "http://localhost:7350/2015-03-31/functions/function/invocations" \ + -d '{"query":"space","limit":2}' +``` + +And because the emulator runs one invocation at a time per container, wait for a call to return before sending the next one. + +## Invoking an `Http*` handler returns `400` or ignores query parameters + +**Symptom:** You started the container with `HttpGetMovies`, `HttpGetMovieById` or `HttpSearchReviews` as the handler and sent `{"query":"space"}`, and the function returned `400` or treated every parameter as empty. + +The default container entrypoint (`SearchMovies`) takes the plain JSON request object. The `Http*` handlers are wired for API Gateway HTTP API (payload format 2.0), and the emulator doesn't translate raw HTTP into an API Gateway event — you pass the event envelope that API Gateway would have sent: + +```bash +curl -X POST "http://localhost:7350/2015-03-31/functions/function/invocations" \ + -d '{ "version": "2.0", "routeKey": "GET /movies", "rawPath": "/movies", "queryStringParameters": { "query": "space", "limit": "2" }, "requestContext": { "http": { "method": "GET", "path": "/movies" } } }' +``` + +See [Run it locally](/lambda/guides/run-locally/) for switching the container handler. + +## Port 7350 is already in use + +**Symptom:** `docker compose up` fails with `Bind for 0.0.0.0:7350 failed: port is already allocated`. + +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Lambda Function uses `7350` to `7359` (`7350` Lambda runtime emulator, `7352` Aspire dashboard, `7353` and `7354` OpenTelemetry Collector). A clash usually means another copy of this template is still running. + +- Check what's running in Docker and stop it: + ```bash + docker compose ps + docker compose down + ``` +- Find a stray host process holding the port (`lsof -i :7350` on macOS and Linux, `netstat -ano | findstr :7350` on Windows) and stop it. +- To move a Docker port, change the left-hand side of its mapping in `docker-compose.yml` (for example `"7355:8080"`; keep the right-hand side as `8080`, which is what the Lambda emulator listens on inside the container) and check the mapped port with: + ```bash + docker compose port function 8080 + ``` + +## `.NET SDK` version refused by `dotnet new` or `global.json` + +**Symptom:** `dotnet new cleanlambdafunction` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. + +Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). + +- Check which SDKs are installed: + ```bash + dotnet --list-sdks + ``` +- Install the current stable [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). If you only have a preview SDK installed on the machine, either install the stable SDK alongside it or set `"allowPrerelease": true` in `global.json`. + +## `--include-auth` is not recognised + +**Symptom:** Running `dotnet new cleanlambdafunction --include-auth` fails with `Error: Invalid option(s): --include-auth`. + +Unlike the four HTTP server templates, Clean Lambda Function doesn't have an `--include-auth` template option. In AWS Lambda, authentication sits in front of the function — as an IAM policy on the function or a JWT authoriser on the API Gateway HTTP API in `src/Presentation/serverless.template` — rather than middleware inside the handler. If you copy a `dotnet new` command from one of the HTTP templates and include `--include-auth` without `--authority`, those templates exit with code `102`; on Lambda, omit `--include-auth` altogether and see [Secure the function](/lambda/guides/secure-the-function/) for adding an API Gateway JWT authoriser or IAM auth. + +## Docker is not running + +**Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. + +Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build` or `dotnet test`; the integration tests invoke the handler in-process against an in-memory SQLite database. + +## `SQLite Error 5: 'database is locked'` + +**Symptom:** A function invocation fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. + +Inside the container, the function writes to `/tmp/movie-reviews.db`. If that file gets wedged during local testing, recreate the container so `/tmp/movie-reviews.db` is rebuilt and re-seeded from scratch: + +```bash +docker compose down +docker compose up -d --build +``` diff --git a/src/content/docs/mcp/getting-started.mdx b/src/content/docs/mcp/getting-started.mdx index 2bfbf7d..a9f154e 100644 --- a/src/content/docs/mcp/getting-started.mdx +++ b/src/content/docs/mcp/getting-started.mdx @@ -98,6 +98,8 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ +Hit a snag? Check [Troubleshooting](/mcp/reference/troubleshooting/). + ## Where to next diff --git a/src/content/docs/mcp/reference/troubleshooting.mdx b/src/content/docs/mcp/reference/troubleshooting.mdx new file mode 100644 index 0000000..e3a34a7 --- /dev/null +++ b/src/content/docs/mcp/reference/troubleshooting.mdx @@ -0,0 +1,102 @@ +--- +title: "Troubleshooting" +description: "Fixes for the common snags when creating, building and running a solution." +sidebar: + order: 6 +--- + +The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, an Inspector pointed at the wrong host, or Docker taking a nap. + +## The MCP Inspector at `http://localhost:7325` won't connect + +**Symptom:** Opening `http://localhost:7325` and clicking **Connect** fails to reach the MCP server. + +When started with `docker compose up -d --build`, the MCP Inspector runs inside the Compose network (`cleanmodelcontextprotocol_network`), not on your host machine. Inside that network the MCP server's hostname is `api`, not `localhost`. + +- In the Docker-hosted Inspector at `http://localhost:7325`, keep **Transport Type** set to `Streamable HTTP` and **URL** set to `http://api:7320/mcp`. If you change the URL to `http://localhost:7320/mcp`, the Inspector container tries to connect to itself and fails. +- If you run a separate Inspector directly on your host machine (for example `npx @modelcontextprotocol/inspector`), point it at `http://localhost:7320/mcp` for Docker or `https://localhost:7321/mcp` for `dotnet run`. + +## The chat demo on port 7326 isn't running + +**Symptom:** `http://localhost:7326` refuses to connect after `docker compose up -d --build`, or the `chat` service isn't in `docker-compose.yml`. + +- The Open WebUI chat container sits behind the `demo` Compose profile so a normal `docker compose up` doesn't pull a multi-gigabyte image. Start it with: + ```bash + docker compose --profile demo up -d --build + ``` +- Open `http://localhost:7326`. It needs no login (`WEBUI_AUTH` is off) and no API key — it uses Kilo's free gateway (`kilo-auto/free`) with the MCP server already connected. +- If you generated the solution with `--include-auth`, the `chat` service is left out of `docker-compose.yml` because Open WebUI has no way to acquire and send an OAuth bearer token to the MCP server. + +## Port 7320 or 7321 is already in use + +**Symptom:** `dotnet run` stops with `Failed to bind to address https://127.0.0.1:7321: address already in use`, or `docker compose up` fails with `Bind for 0.0.0.0:7320 failed: port is already allocated`. + +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Model Context Protocol uses `7320` to `7329` (`7320` HTTP, `7321` HTTPS, `7322` Aspire dashboard, `7323` and `7324` OpenTelemetry Collector, `7325` MCP Inspector, `7326` Open WebUI chat demo). A clash usually means another copy of this template is still running. + +- Check what's running in Docker and stop it: + ```bash + docker compose --profile demo ps + docker compose --profile demo down + ``` +- Find a stray host process holding the port (`lsof -i :7320` on macOS and Linux, `netstat -ano | findstr :7320` on Windows) and stop it. +- To move a Docker port, change the left-hand side of its mapping in `docker-compose.yml` and check the mapped port with: + ```bash + docker compose port api 7320 + ``` +- To move the `dotnet run` ports, edit `applicationUrl` in `src/Presentation/Properties/launchSettings.json`. + +## Untrusted certificate or empty `curl` reply on `dotnet run` + +**Symptom:** `curl` or an MCP client fails against `https://localhost:7321/mcp` with a TLS certificate error, or calling `http://localhost:7320/mcp` under `dotnet run` returns `307 Temporary Redirect`. + +In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7320` and `https://localhost:7321` and redirects HTTP to HTTPS. + +- Trust the .NET development certificate once on your machine: + ```bash + dotnet dev-certs https --trust + ``` +- Point local MCP clients and `curl` at `https://localhost:7321/mcp` when using `dotnet run`. +- Under `docker compose up -d --build`, the container runs in the `docker` environment and serves plain HTTP at `http://localhost:7320/mcp` with no redirect. + +## `.NET SDK` version refused by `dotnet new` or `global.json` + +**Symptom:** `dotnet new cleanmodelcontextprotocol` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. + +Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). + +- Check which SDKs are installed: + ```bash + dotnet --list-sdks + ``` +- Install the current stable [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). If you only have a preview SDK installed on the machine, either install the stable SDK alongside it or set `"allowPrerelease": true` in `global.json`. + +## `--include-auth` fails with exit code 102 + +**Symptom:** Running `dotnet new cleanmodelcontextprotocol --include-auth` stops before writing any files and exits with code `102` (`Invalid option(s)` / missing mandatory option `--authority`). + +When `--include-auth` is switched on, `--authority` is required so a generated solution never starts with a blank OAuth issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: + +```bash +dotnet new cleanmodelcontextprotocol --name WorksOnMyMachine.Movies \ + --include-auth \ + --authority "https://your-tenant.example.com" \ + --audience "https://mcp.example.com" +``` + +See [Secure the server](/mcp/guides/secure-the-server/) for configuring OAuth 2.1 tokens after generation. + +## Docker is not running + +**Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. + +Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. + +## `SQLite Error 5: 'database is locked'` + +**Symptom:** Startup migration or a write tool fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. + +`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file — usually a second `dotnet run` terminal or a database viewer. + +- Stop the other process holding `src/Presentation/movie-reviews.db`. +- If you want to wipe the local database and re-seed the sample data from scratch, stop the server, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the server again. +- In Docker Compose, `docker compose down -v` removes the `movie-reviews-data` volume so the next `docker compose up -d` starts with a fresh database. diff --git a/src/content/docs/minimalapi/getting-started.mdx b/src/content/docs/minimalapi/getting-started.mdx index 2587918..33f742c 100644 --- a/src/content/docs/minimalapi/getting-started.mdx +++ b/src/content/docs/minimalapi/getting-started.mdx @@ -91,6 +91,8 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ +Hit a snag? Check [Troubleshooting](/minimalapi/reference/troubleshooting/). + ## Where to next diff --git a/src/content/docs/minimalapi/reference/troubleshooting.mdx b/src/content/docs/minimalapi/reference/troubleshooting.mdx new file mode 100644 index 0000000..0a04b82 --- /dev/null +++ b/src/content/docs/minimalapi/reference/troubleshooting.mdx @@ -0,0 +1,91 @@ +--- +title: "Troubleshooting" +description: "Fixes for the common snags when creating, building and running a solution." +sidebar: + order: 5 +--- + +The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Docker taking a nap. + +## Port 7310 or 7311 is already in use + +**Symptom:** `dotnet run` stops with `Failed to bind to address https://127.0.0.1:7311: address already in use`, or `docker compose up` fails with `Bind for 0.0.0.0:7310 failed: port is already allocated`. + +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Minimal API uses `7310` to `7319` (`7310` HTTP, `7311` HTTPS, `7312` Aspire dashboard, `7313` and `7314` OpenTelemetry Collector). A clash usually means another copy of this template is still running. + +- Check what's running in Docker and stop it: + ```bash + docker compose ps + docker compose down + ``` +- Find a stray host process holding the port (`lsof -i :7310` on macOS and Linux, `netstat -ano | findstr :7310` on Windows) and stop it. +- To move a Docker port, change the left-hand side of its mapping in `docker-compose.yml` (for example `"7315:7310"`) and check the mapped port with: + ```bash + docker compose port api 7310 + ``` +- To move the `dotnet run` ports, edit `applicationUrl` in `src/Presentation/Properties/launchSettings.json`. + +## Browser certificate warning or empty `curl` reply on `dotnet run` + +**Symptom:** Your browser warns that `https://localhost:7311` is untrusted, `curl` fails with `SSL certificate problem: unable to get local issuer certificate`, or calling `http://localhost:7310` returns `307 Temporary Redirect` with an empty body. + +In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7310` and `https://localhost:7311` and redirects HTTP to HTTPS. + +- Trust the .NET development certificate once on your machine, then restart your browser: + ```bash + dotnet dev-certs https --trust + ``` +- Call `https://localhost:7311` directly when using `dotnet run`, or pass `-L` to `curl` so it follows the redirect. +- Under `docker compose up -d --build`, the container runs in the `docker` environment and serves plain HTTP on `http://localhost:7310` with no redirect and no certificate needed. + +## `.NET SDK` version refused by `dotnet new` or `global.json` + +**Symptom:** `dotnet new cleanminimalapi` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. + +Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). + +- Check which SDKs are installed: + ```bash + dotnet --list-sdks + ``` +- Install the current stable [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). If you only have a preview SDK installed on the machine, either install the stable SDK alongside it or set `"allowPrerelease": true` in `global.json`. + +## `--include-auth` fails with exit code 102 + +**Symptom:** Running `dotnet new cleanminimalapi --include-auth` stops before writing any files and exits with code `102` (`Invalid option(s)` / missing mandatory option `--authority`). + +When `--include-auth` is switched on, `--authority` is required so a generated solution never starts with a blank JWT issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: + +```bash +dotnet new cleanminimalapi --name WorksOnMyMachine.Movies \ + --include-auth \ + --authority "https://your-tenant.example.com" \ + --audience "https://api.example.com" +``` + +See [Secure the API](/minimalapi/guides/secure-the-api/) for configuring tokens after generation. + +## Docker is not running + +**Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. + +Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. + +## `SQLite Error 5: 'database is locked'` + +**Symptom:** Startup migration or a write request fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. + +`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file — usually a second `dotnet run` terminal or a database viewer. + +- Stop the other process holding `src/Presentation/movie-reviews.db`. +- If you want to wipe the local database and re-seed the sample data from scratch, stop the API, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the API again. +- In Docker Compose, `docker compose down -v` removes the `movie-reviews-data` volume so the next `docker compose up -d` starts with a fresh database. + +## Scalar or `Presentation.http` returns `401 Unauthorized` + +**Symptom:** Requests return `401 Unauthorized` when the solution was created with `--include-auth`. + +Every `/api/*` route requires a valid JWT bearer token when authentication is included. + +- In Scalar (`/scalar`), click **Authorize** at the top of the page and paste a bearer token issued by your `--authority`. +- In `src/Presentation/Presentation.http`, paste your token into the `@token =` variable at the top of the file before sending requests. diff --git a/src/content/docs/webapi/getting-started.mdx b/src/content/docs/webapi/getting-started.mdx index bfe3f9e..0f96c06 100644 --- a/src/content/docs/webapi/getting-started.mdx +++ b/src/content/docs/webapi/getting-started.mdx @@ -91,6 +91,8 @@ You need the [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). [ +Hit a snag? Check [Troubleshooting](/webapi/reference/troubleshooting/). + ## Where to next diff --git a/src/content/docs/webapi/reference/troubleshooting.mdx b/src/content/docs/webapi/reference/troubleshooting.mdx new file mode 100644 index 0000000..869813c --- /dev/null +++ b/src/content/docs/webapi/reference/troubleshooting.mdx @@ -0,0 +1,91 @@ +--- +title: "Troubleshooting" +description: "Fixes for the common snags when creating, building and running a solution." +sidebar: + order: 5 +--- + +The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Docker taking a nap. + +## Port 7340 or 7341 is already in use + +**Symptom:** `dotnet run` stops with `Failed to bind to address https://127.0.0.1:7341: address already in use`, or `docker compose up` fails with `Bind for 0.0.0.0:7340 failed: port is already allocated`. + +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Web API uses `7340` to `7349` (`7340` HTTP, `7341` HTTPS, `7342` Aspire dashboard, `7343` and `7344` OpenTelemetry Collector). A clash usually means another copy of this template is still running. + +- Check what's running in Docker and stop it: + ```bash + docker compose ps + docker compose down + ``` +- Find a stray host process holding the port (`lsof -i :7340` on macOS and Linux, `netstat -ano | findstr :7340` on Windows) and stop it. +- To move a Docker port, change the left-hand side of its mapping in `docker-compose.yml` (for example `"7345:7340"`) and check the mapped port with: + ```bash + docker compose port api 7340 + ``` +- To move the `dotnet run` ports, edit `applicationUrl` in `src/Presentation/Properties/launchSettings.json`. + +## Browser certificate warning or empty `curl` reply on `dotnet run` + +**Symptom:** Your browser warns that `https://localhost:7341` is untrusted, `curl` fails with `SSL certificate problem: unable to get local issuer certificate`, or calling `http://localhost:7340` returns `307 Temporary Redirect` with an empty body. + +In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7340` and `https://localhost:7341` and redirects HTTP to HTTPS. + +- Trust the .NET development certificate once on your machine, then restart your browser: + ```bash + dotnet dev-certs https --trust + ``` +- Call `https://localhost:7341` directly when using `dotnet run`, or pass `-L` to `curl` so it follows the redirect. +- Under `docker compose up -d --build`, the container runs in the `docker` environment and serves plain HTTP on `http://localhost:7340` with no redirect and no certificate needed. + +## `.NET SDK` version refused by `dotnet new` or `global.json` + +**Symptom:** `dotnet new cleanwebapi` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. + +Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). + +- Check which SDKs are installed: + ```bash + dotnet --list-sdks + ``` +- Install the current stable [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0). If you only have a preview SDK installed on the machine, either install the stable SDK alongside it or set `"allowPrerelease": true` in `global.json`. + +## `--include-auth` fails with exit code 102 + +**Symptom:** Running `dotnet new cleanwebapi --include-auth` stops before writing any files and exits with code `102` (`Invalid option(s)` / missing mandatory option `--authority`). + +When `--include-auth` is switched on, `--authority` is required so a generated solution never starts with a blank JWT issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: + +```bash +dotnet new cleanwebapi --name WorksOnMyMachine.Movies \ + --include-auth \ + --authority "https://your-tenant.example.com" \ + --audience "https://api.example.com" +``` + +See [Secure the API](/webapi/guides/secure-the-api/) for configuring tokens after generation. + +## Docker is not running + +**Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. + +Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. + +## `SQLite Error 5: 'database is locked'` + +**Symptom:** Startup migration or a write request fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. + +`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file — usually a second `dotnet run` terminal or a database viewer. + +- Stop the other process holding `src/Presentation/movie-reviews.db`. +- If you want to wipe the local database and re-seed the sample data from scratch, stop the API, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the API again. +- In Docker Compose, `docker compose down -v` removes the `movie-reviews-data` volume so the next `docker compose up -d` starts with a fresh database. + +## Scalar or `Presentation.http` returns `401 Unauthorized` + +**Symptom:** Requests return `401 Unauthorized` when the solution was created with `--include-auth`. + +Every `/api/*` controller action requires a valid JWT bearer token when authentication is included. + +- In Scalar (`/scalar`), click **Authorize** at the top of the page and paste a bearer token issued by your `--authority`. +- In `src/Presentation/Presentation.http`, paste your token into the `@token =` variable at the top of the file before sending requests. From 4e17e7541ab395b6de5a7c4cc46054843e76b88e Mon Sep 17 00:00:00 2001 From: Stephen Walsh <868017+stphnwlsh@users.noreply.github.com> Date: Sun, 8 Nov 2026 00:01:23 +0000 Subject: [PATCH 2/4] Fix the schema snapshot and Lambda handler details on the troubleshooting pages --- .../docs/graphql/reference/troubleshooting.mdx | 10 +++++----- .../docs/lambda/reference/troubleshooting.mdx | 12 ++++++------ src/content/docs/mcp/reference/troubleshooting.mdx | 6 +++--- .../docs/minimalapi/reference/troubleshooting.mdx | 6 +++--- .../docs/webapi/reference/troubleshooting.mdx | 6 +++--- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/content/docs/graphql/reference/troubleshooting.mdx b/src/content/docs/graphql/reference/troubleshooting.mdx index 7f818b3..a149e29 100644 --- a/src/content/docs/graphql/reference/troubleshooting.mdx +++ b/src/content/docs/graphql/reference/troubleshooting.mdx @@ -11,13 +11,13 @@ The template is set up to work out of the box, which mostly means the things tha **Symptom:** Opening `https://localhost:7331/graphql` (or `http://localhost:7330/graphql` in Docker) shows a **Sign in** button or prompts you to connect a ChilliCream cloud account. -Nitro is ChilliCream's GraphQL IDE embedded in Hot Chocolate. Its **Sign in** button is only for syncing workspaces with ChilliCream's cloud service — you don't need an account to browse the schema, write queries or run mutations against your local API. Close or ignore the prompt and run queries straight from the editor. +Nitro is ChilliCream's GraphQL IDE embedded in Hot Chocolate. Its **Sign in** button is only for syncing workspaces with ChilliCream's cloud service. You don't need an account to browse the schema, write queries or run mutations against your local API. Close or ignore the prompt and run queries straight from the editor. -## `SchemaMatchesSnapshot` fails after changing a GraphQL type +## `Schema_ShouldMatch_Snapshot` fails after changing a GraphQL type -**Symptom:** `dotnet test` fails in `tests/Presentation.Tests.Unit/SchemaSnapshotTests.cs` (`SchemaMatchesSnapshot`). +**Symptom:** `dotnet test` fails in `tests/Presentation.Tests.Integration/GraphQL/Schema/SchemaTests.cs` (`Schema_ShouldMatch_Snapshot`). -The unit tests compare the built GraphQL schema against `tests/Presentation.Tests.Unit/Schema.graphql` so accidental breaking changes never slip past review. When you intentionally add or change a query, mutation, type or description, update `tests/Presentation.Tests.Unit/Schema.graphql` to match (see [Add a field](/graphql/guides/add-a-field/)). +The integration tests compare the built GraphQL schema against `tests/Presentation.Tests.Integration/GraphQL/Schema/schema.graphql` so accidental breaking changes never slip past review. When you intentionally add or change a query, mutation, type or description, update `tests/Presentation.Tests.Integration/GraphQL/Schema/schema.graphql` to match (see [Add a field](/graphql/guides/add-a-field/)). ## Port 7330 or 7331 is already in use @@ -87,7 +87,7 @@ Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` **Symptom:** Startup migration or a mutation fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. -`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file — usually a second `dotnet run` terminal or a database viewer. +`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. - Stop the other process holding `src/Presentation/movie-reviews.db`. - If you want to wipe the local database and re-seed the sample data from scratch, stop the API, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the API again. diff --git a/src/content/docs/lambda/reference/troubleshooting.mdx b/src/content/docs/lambda/reference/troubleshooting.mdx index b53ae25..4eef3b9 100644 --- a/src/content/docs/lambda/reference/troubleshooting.mdx +++ b/src/content/docs/lambda/reference/troubleshooting.mdx @@ -1,11 +1,11 @@ --- -title: Troubleshooting -description: Fixes for the common snags when creating, building and invoking a solution locally. +title: "Troubleshooting" +description: "Fixes for the common snags when creating, building and invoking a solution locally." sidebar: order: 5 --- -The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, calling the Lambda emulator like an ordinary web server, or Docker taking a nap. +The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, calling the Lambda emulator like an ordinary web server, or Docker not running. ## Calling `http://localhost:7350` returns `404` or hangs @@ -22,9 +22,9 @@ And because the emulator runs one invocation at a time per container, wait for a ## Invoking an `Http*` handler returns `400` or ignores query parameters -**Symptom:** You started the container with `HttpGetMovies`, `HttpGetMovieById` or `HttpSearchReviews` as the handler and sent `{"query":"space"}`, and the function returned `400` or treated every parameter as empty. +**Symptom:** You started the container with `HttpGetMovies`, `HttpGetAuthors` or `HttpGetReviews` as the handler and sent `{"query":"space"}`, and the function returned `400` or treated every parameter as empty. -The default container entrypoint (`SearchMovies`) takes the plain JSON request object. The `Http*` handlers are wired for API Gateway HTTP API (payload format 2.0), and the emulator doesn't translate raw HTTP into an API Gateway event — you pass the event envelope that API Gateway would have sent: +The default container handler (`GetMovies`) takes the plain JSON request object. The `Http*` handlers are wired for API Gateway HTTP API (payload format 2.0), and the emulator doesn't translate raw HTTP into an API Gateway event, so you pass the event envelope that API Gateway would have sent: ```bash curl -X POST "http://localhost:7350/2015-03-31/functions/function/invocations" \ @@ -66,7 +66,7 @@ Both `.template.config/template.json` and the generated `global.json` require a **Symptom:** Running `dotnet new cleanlambdafunction --include-auth` fails with `Error: Invalid option(s): --include-auth`. -Unlike the four HTTP server templates, Clean Lambda Function doesn't have an `--include-auth` template option. In AWS Lambda, authentication sits in front of the function — as an IAM policy on the function or a JWT authoriser on the API Gateway HTTP API in `src/Presentation/serverless.template` — rather than middleware inside the handler. If you copy a `dotnet new` command from one of the HTTP templates and include `--include-auth` without `--authority`, those templates exit with code `102`; on Lambda, omit `--include-auth` altogether and see [Secure the function](/lambda/guides/secure-the-function/) for adding an API Gateway JWT authoriser or IAM auth. +Unlike the four HTTP server templates, Clean Lambda Function doesn't have an `--include-auth` template option. In AWS Lambda, authentication sits in front of the function, as an IAM policy on the function or a JWT authoriser on the API Gateway HTTP API in `src/Presentation/serverless.template`, rather than middleware inside the handler. If you copy a `dotnet new` command from one of the HTTP templates and include `--include-auth` without `--authority`, those templates exit with code `102`; on Lambda, omit `--include-auth` altogether and see [Secure the function](/lambda/guides/secure-the-function/) for adding an API Gateway JWT authoriser or IAM auth. ## Docker is not running diff --git a/src/content/docs/mcp/reference/troubleshooting.mdx b/src/content/docs/mcp/reference/troubleshooting.mdx index e3a34a7..1bad136 100644 --- a/src/content/docs/mcp/reference/troubleshooting.mdx +++ b/src/content/docs/mcp/reference/troubleshooting.mdx @@ -5,7 +5,7 @@ sidebar: order: 6 --- -The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, an Inspector pointed at the wrong host, or Docker taking a nap. +The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, an Inspector pointed at the wrong host, or Docker not running. ## The MCP Inspector at `http://localhost:7325` won't connect @@ -24,7 +24,7 @@ When started with `docker compose up -d --build`, the MCP Inspector runs inside ```bash docker compose --profile demo up -d --build ``` -- Open `http://localhost:7326`. It needs no login (`WEBUI_AUTH` is off) and no API key — it uses Kilo's free gateway (`kilo-auto/free`) with the MCP server already connected. +- Open `http://localhost:7326`. It needs no login (`WEBUI_AUTH` is off) and no API key. It uses Kilo's free gateway (`kilo-auto/free`) with the MCP server already connected. - If you generated the solution with `--include-auth`, the `chat` service is left out of `docker-compose.yml` because Open WebUI has no way to acquire and send an OAuth bearer token to the MCP server. ## Port 7320 or 7321 is already in use @@ -95,7 +95,7 @@ Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` **Symptom:** Startup migration or a write tool fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. -`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file — usually a second `dotnet run` terminal or a database viewer. +`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. - Stop the other process holding `src/Presentation/movie-reviews.db`. - If you want to wipe the local database and re-seed the sample data from scratch, stop the server, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the server again. diff --git a/src/content/docs/minimalapi/reference/troubleshooting.mdx b/src/content/docs/minimalapi/reference/troubleshooting.mdx index 0a04b82..aa596fc 100644 --- a/src/content/docs/minimalapi/reference/troubleshooting.mdx +++ b/src/content/docs/minimalapi/reference/troubleshooting.mdx @@ -5,7 +5,7 @@ sidebar: order: 5 --- -The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Docker taking a nap. +The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Docker not running. ## Port 7310 or 7311 is already in use @@ -75,7 +75,7 @@ Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` **Symptom:** Startup migration or a write request fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. -`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file — usually a second `dotnet run` terminal or a database viewer. +`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. - Stop the other process holding `src/Presentation/movie-reviews.db`. - If you want to wipe the local database and re-seed the sample data from scratch, stop the API, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the API again. @@ -88,4 +88,4 @@ Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` Every `/api/*` route requires a valid JWT bearer token when authentication is included. - In Scalar (`/scalar`), click **Authorize** at the top of the page and paste a bearer token issued by your `--authority`. -- In `src/Presentation/Presentation.http`, paste your token into the `@token =` variable at the top of the file before sending requests. +- In `src/Presentation/Presentation.http`, uncomment the `@token` line at the top of the file, paste your token after it, and uncomment the `Authorization` header on each request. diff --git a/src/content/docs/webapi/reference/troubleshooting.mdx b/src/content/docs/webapi/reference/troubleshooting.mdx index 869813c..1c0371e 100644 --- a/src/content/docs/webapi/reference/troubleshooting.mdx +++ b/src/content/docs/webapi/reference/troubleshooting.mdx @@ -5,7 +5,7 @@ sidebar: order: 5 --- -The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Docker taking a nap. +The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Docker not running. ## Port 7340 or 7341 is already in use @@ -75,7 +75,7 @@ Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` **Symptom:** Startup migration or a write request fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. -`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file — usually a second `dotnet run` terminal or a database viewer. +`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. - Stop the other process holding `src/Presentation/movie-reviews.db`. - If you want to wipe the local database and re-seed the sample data from scratch, stop the API, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the API again. @@ -88,4 +88,4 @@ Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` Every `/api/*` controller action requires a valid JWT bearer token when authentication is included. - In Scalar (`/scalar`), click **Authorize** at the top of the page and paste a bearer token issued by your `--authority`. -- In `src/Presentation/Presentation.http`, paste your token into the `@token =` variable at the top of the file before sending requests. +- In `src/Presentation/Presentation.http`, uncomment the `@token` line at the top of the file, paste your token after it, and uncomment the `Authorization` header on each request. From 0a69e6cdc0a42dee180f92fceb19579795e72d9b Mon Sep 17 00:00:00 2001 From: Stephen Walsh Date: Sat, 7 Nov 2026 19:58:09 -0600 Subject: [PATCH 3/4] Give each troubleshooting page its own opening line --- src/content/docs/graphql/reference/troubleshooting.mdx | 2 +- src/content/docs/lambda/reference/troubleshooting.mdx | 2 +- src/content/docs/mcp/reference/troubleshooting.mdx | 2 +- src/content/docs/minimalapi/reference/troubleshooting.mdx | 2 +- src/content/docs/webapi/reference/troubleshooting.mdx | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/content/docs/graphql/reference/troubleshooting.mdx b/src/content/docs/graphql/reference/troubleshooting.mdx index a149e29..ed3da48 100644 --- a/src/content/docs/graphql/reference/troubleshooting.mdx +++ b/src/content/docs/graphql/reference/troubleshooting.mdx @@ -5,7 +5,7 @@ sidebar: order: 5 --- -The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Nitro asking you to sign in to a cloud you don't use. +Most first-run problems aren't in the schema. They're in the machine around it: a port that's already taken, a certificate your browser hasn't met yet, or Nitro asking you to sign in to a cloud you don't use. ## Nitro asks you to "Sign in" diff --git a/src/content/docs/lambda/reference/troubleshooting.mdx b/src/content/docs/lambda/reference/troubleshooting.mdx index 4eef3b9..54f8b57 100644 --- a/src/content/docs/lambda/reference/troubleshooting.mdx +++ b/src/content/docs/lambda/reference/troubleshooting.mdx @@ -5,7 +5,7 @@ sidebar: order: 5 --- -The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, calling the Lambda emulator like an ordinary web server, or Docker not running. +Most first-run problems aren't in the functions. They're in how they get called: a port that's already taken, the Lambda emulator treated like a web server (it isn't one), or Docker that hasn't woken up. ## Calling `http://localhost:7350` returns `404` or hangs diff --git a/src/content/docs/mcp/reference/troubleshooting.mdx b/src/content/docs/mcp/reference/troubleshooting.mdx index 1bad136..1af7766 100644 --- a/src/content/docs/mcp/reference/troubleshooting.mdx +++ b/src/content/docs/mcp/reference/troubleshooting.mdx @@ -5,7 +5,7 @@ sidebar: order: 6 --- -The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, an Inspector pointed at the wrong host, or Docker not running. +Most first-run problems aren't in the server. They're in the plumbing around it: a port that's already taken, an Inspector looking for the server on the wrong host, or Docker that hasn't woken up. ## The MCP Inspector at `http://localhost:7325` won't connect diff --git a/src/content/docs/minimalapi/reference/troubleshooting.mdx b/src/content/docs/minimalapi/reference/troubleshooting.mdx index aa596fc..4d7347c 100644 --- a/src/content/docs/minimalapi/reference/troubleshooting.mdx +++ b/src/content/docs/minimalapi/reference/troubleshooting.mdx @@ -5,7 +5,7 @@ sidebar: order: 5 --- -The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Docker not running. +Most first-run problems aren't in the code. They're in the machine around it: a port that's already taken, a certificate your browser hasn't met yet, or Docker that hasn't woken up. ## Port 7310 or 7311 is already in use diff --git a/src/content/docs/webapi/reference/troubleshooting.mdx b/src/content/docs/webapi/reference/troubleshooting.mdx index 1c0371e..10dd6c9 100644 --- a/src/content/docs/webapi/reference/troubleshooting.mdx +++ b/src/content/docs/webapi/reference/troubleshooting.mdx @@ -5,7 +5,7 @@ sidebar: order: 5 --- -The template is set up to work out of the box, which mostly means the things that go wrong are environmental: a port already taken, a certificate the browser hasn't met yet, or Docker not running. +Most first-run problems aren't in the controllers. They're in the machine around it: a port that's already taken, a certificate your browser hasn't met yet, or Docker that hasn't woken up. ## Port 7340 or 7341 is already in use From 39dc21b958dfd9d5cdbd26cf6608d7a084f60193 Mon Sep 17 00:00:00 2001 From: Stephen Walsh <868017+stphnwlsh@users.noreply.github.com> Date: Sun, 8 Nov 2026 01:58:51 +0000 Subject: [PATCH 4/4] Give the troubleshooting pages the house voice and fix the HTTP address on the run-locally pages --- src/content/docs/graphql/guides/run-locally.mdx | 2 +- .../docs/graphql/reference/troubleshooting.mdx | 16 ++++++++-------- .../docs/lambda/reference/troubleshooting.mdx | 6 +++--- src/content/docs/mcp/guides/run-locally.mdx | 2 +- .../docs/mcp/reference/troubleshooting.mdx | 14 +++++++------- .../docs/minimalapi/guides/run-locally.mdx | 2 +- .../minimalapi/reference/troubleshooting.mdx | 14 +++++++------- src/content/docs/webapi/guides/run-locally.mdx | 2 +- .../docs/webapi/reference/troubleshooting.mdx | 14 +++++++------- 9 files changed, 36 insertions(+), 36 deletions(-) diff --git a/src/content/docs/graphql/guides/run-locally.mdx b/src/content/docs/graphql/guides/run-locally.mdx index fa51c50..2967e23 100644 --- a/src/content/docs/graphql/guides/run-locally.mdx +++ b/src/content/docs/graphql/guides/run-locally.mdx @@ -17,7 +17,7 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data dotnet run --project ./src/Presentation ``` - `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7331](https://localhost:7331), and on `https://localhost:7331`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7331](https://localhost:7331), and on `http://localhost:7330`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. ```bash diff --git a/src/content/docs/graphql/reference/troubleshooting.mdx b/src/content/docs/graphql/reference/troubleshooting.mdx index ed3da48..eea0aca 100644 --- a/src/content/docs/graphql/reference/troubleshooting.mdx +++ b/src/content/docs/graphql/reference/troubleshooting.mdx @@ -11,19 +11,19 @@ Most first-run problems aren't in the schema. They're in the machine around it: **Symptom:** Opening `https://localhost:7331/graphql` (or `http://localhost:7330/graphql` in Docker) shows a **Sign in** button or prompts you to connect a ChilliCream cloud account. -Nitro is ChilliCream's GraphQL IDE embedded in Hot Chocolate. Its **Sign in** button is only for syncing workspaces with ChilliCream's cloud service. You don't need an account to browse the schema, write queries or run mutations against your local API. Close or ignore the prompt and run queries straight from the editor. +Nitro is ChilliCream's GraphQL IDE embedded in Hot Chocolate. Its **Sign in** button is only for syncing workspaces with ChilliCream's cloud service. You don't need an account to browse the schema, write queries or run mutations against your local API. Nitro works perfectly well as a guest, so close the prompt and run queries straight from the editor. ## `Schema_ShouldMatch_Snapshot` fails after changing a GraphQL type **Symptom:** `dotnet test` fails in `tests/Presentation.Tests.Integration/GraphQL/Schema/SchemaTests.cs` (`Schema_ShouldMatch_Snapshot`). -The integration tests compare the built GraphQL schema against `tests/Presentation.Tests.Integration/GraphQL/Schema/schema.graphql` so accidental breaking changes never slip past review. When you intentionally add or change a query, mutation, type or description, update `tests/Presentation.Tests.Integration/GraphQL/Schema/schema.graphql` to match (see [Add a field](/graphql/guides/add-a-field/)). +The integration tests compare the built GraphQL schema against `tests/Presentation.Tests.Integration/GraphQL/Schema/schema.graphql` so accidental breaking changes never slip past review. A failure here means the snapshot noticed something, which is its whole job. When you intentionally add or change a query, mutation, type or description, update `tests/Presentation.Tests.Integration/GraphQL/Schema/schema.graphql` to match (see [Add a field](/graphql/guides/add-a-field/)). ## Port 7330 or 7331 is already in use **Symptom:** `dotnet run` stops with `Failed to bind to address https://127.0.0.1:7331: address already in use`, or `docker compose up` fails with `Bind for 0.0.0.0:7330 failed: port is already allocated`. -Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean GraphQL API uses `7330` to `7339` (`7330` HTTP, `7331` HTTPS, `7332` Aspire dashboard, `7333` and `7334` OpenTelemetry Collector). A clash usually means another copy of this template is still running. +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean GraphQL API uses `7330` to `7339` (`7330` HTTP, `7331` HTTPS, `7332` Aspire dashboard, `7333` and `7334` OpenTelemetry Collector). A clash usually means an earlier copy of this template is still running somewhere, quietly hogging the port. - Check what's running in Docker and stop it: ```bash @@ -41,7 +41,7 @@ Each Lean Mean Clean template has its own block of ten ports so different templa **Symptom:** Your browser warns that `https://localhost:7331` is untrusted, `curl` fails with `SSL certificate problem: unable to get local issuer certificate`, or calling `http://localhost:7330/graphql` returns `307 Temporary Redirect` with an empty body. -In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7330` and `https://localhost:7331` and redirects HTTP to HTTPS. +In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7330` and `https://localhost:7331` and redirects HTTP to HTTPS. The development certificate is new to your machine, so your browser treats it like a stranger until you introduce them. - Trust the .NET development certificate once on your machine, then restart your browser: ```bash @@ -54,7 +54,7 @@ In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel **Symptom:** `dotnet new cleangraphqlapi` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. -Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). +Previews are fun, but the template only promises to work on a stable SDK. Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). - Check which SDKs are installed: ```bash @@ -66,7 +66,7 @@ Both `.template.config/template.json` and the generated `global.json` require a **Symptom:** Running `dotnet new cleangraphqlapi --include-auth` stops before writing any files and exits with code `102` (`Invalid option(s)` / missing mandatory option `--authority`). -When `--include-auth` is switched on, `--authority` is required so a generated solution never starts with a blank JWT issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: +When `--include-auth` is switched on, `--authority` is required. Stopping at the door beats shipping a solution with a blank JWT issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: ```bash dotnet new cleangraphqlapi --name WorksOnMyMachine.Movies \ @@ -81,13 +81,13 @@ See [Secure the API](/graphql/guides/secure-the-api/) for sending bearer tokens **Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. -Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. +Docker doesn't start itself, however much we'd like it to. Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. ## `SQLite Error 5: 'database is locked'` **Symptom:** Startup migration or a mutation fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. -`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. +`dotnet run` writes to `src/Presentation/movie-reviews.db`. SQLite lets plenty of readers share a file but only one writer at a time. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. - Stop the other process holding `src/Presentation/movie-reviews.db`. - If you want to wipe the local database and re-seed the sample data from scratch, stop the API, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the API again. diff --git a/src/content/docs/lambda/reference/troubleshooting.mdx b/src/content/docs/lambda/reference/troubleshooting.mdx index 54f8b57..b2964c6 100644 --- a/src/content/docs/lambda/reference/troubleshooting.mdx +++ b/src/content/docs/lambda/reference/troubleshooting.mdx @@ -37,7 +37,7 @@ See [Run it locally](/lambda/guides/run-locally/) for switching the container ha **Symptom:** `docker compose up` fails with `Bind for 0.0.0.0:7350 failed: port is already allocated`. -Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Lambda Function uses `7350` to `7359` (`7350` Lambda runtime emulator, `7352` Aspire dashboard, `7353` and `7354` OpenTelemetry Collector). A clash usually means another copy of this template is still running. +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Lambda Function uses `7350` to `7359` (`7350` Lambda runtime emulator, `7352` Aspire dashboard, `7353` and `7354` OpenTelemetry Collector). A clash usually means an earlier copy of this template is still running somewhere, quietly hogging the port. - Check what's running in Docker and stop it: ```bash @@ -54,7 +54,7 @@ Each Lean Mean Clean template has its own block of ten ports so different templa **Symptom:** `dotnet new cleanlambdafunction` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. -Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). +Previews are fun, but the template only promises to work on a stable SDK. Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). - Check which SDKs are installed: ```bash @@ -72,7 +72,7 @@ Unlike the four HTTP server templates, Clean Lambda Function doesn't have an `-- **Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. -Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build` or `dotnet test`; the integration tests invoke the handler in-process against an in-memory SQLite database. +Docker doesn't start itself, however much we'd like it to. Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build` or `dotnet test`; the integration tests invoke the handler in-process against an in-memory SQLite database. ## `SQLite Error 5: 'database is locked'` diff --git a/src/content/docs/mcp/guides/run-locally.mdx b/src/content/docs/mcp/guides/run-locally.mdx index 2e64fc8..c876794 100644 --- a/src/content/docs/mcp/guides/run-locally.mdx +++ b/src/content/docs/mcp/guides/run-locally.mdx @@ -17,7 +17,7 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data dotnet run --project ./src/Presentation ``` - `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7321](https://localhost:7321), and on `https://localhost:7321`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. The server is at `/mcp`. + `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7321](https://localhost:7321), and on `http://localhost:7320`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. The server is at `/mcp`. ```bash diff --git a/src/content/docs/mcp/reference/troubleshooting.mdx b/src/content/docs/mcp/reference/troubleshooting.mdx index 1af7766..017ebd3 100644 --- a/src/content/docs/mcp/reference/troubleshooting.mdx +++ b/src/content/docs/mcp/reference/troubleshooting.mdx @@ -11,7 +11,7 @@ Most first-run problems aren't in the server. They're in the plumbing around it: **Symptom:** Opening `http://localhost:7325` and clicking **Connect** fails to reach the MCP server. -When started with `docker compose up -d --build`, the MCP Inspector runs inside the Compose network (`cleanmodelcontextprotocol_network`), not on your host machine. Inside that network the MCP server's hostname is `api`, not `localhost`. +When started with `docker compose up -d --build`, the MCP Inspector runs inside the Compose network (`cleanmodelcontextprotocol_network`), not on your host machine. Inside that network the MCP server's hostname is `api`, not `localhost`. To a container, `localhost` is itself, which is a lonely place to look for a server. - In the Docker-hosted Inspector at `http://localhost:7325`, keep **Transport Type** set to `Streamable HTTP` and **URL** set to `http://api:7320/mcp`. If you change the URL to `http://localhost:7320/mcp`, the Inspector container tries to connect to itself and fails. - If you run a separate Inspector directly on your host machine (for example `npx @modelcontextprotocol/inspector`), point it at `http://localhost:7320/mcp` for Docker or `https://localhost:7321/mcp` for `dotnet run`. @@ -31,7 +31,7 @@ When started with `docker compose up -d --build`, the MCP Inspector runs inside **Symptom:** `dotnet run` stops with `Failed to bind to address https://127.0.0.1:7321: address already in use`, or `docker compose up` fails with `Bind for 0.0.0.0:7320 failed: port is already allocated`. -Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Model Context Protocol uses `7320` to `7329` (`7320` HTTP, `7321` HTTPS, `7322` Aspire dashboard, `7323` and `7324` OpenTelemetry Collector, `7325` MCP Inspector, `7326` Open WebUI chat demo). A clash usually means another copy of this template is still running. +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Model Context Protocol uses `7320` to `7329` (`7320` HTTP, `7321` HTTPS, `7322` Aspire dashboard, `7323` and `7324` OpenTelemetry Collector, `7325` MCP Inspector, `7326` Open WebUI chat demo). A clash usually means an earlier copy of this template is still running somewhere, quietly hogging the port. - Check what's running in Docker and stop it: ```bash @@ -49,7 +49,7 @@ Each Lean Mean Clean template has its own block of ten ports so different templa **Symptom:** `curl` or an MCP client fails against `https://localhost:7321/mcp` with a TLS certificate error, or calling `http://localhost:7320/mcp` under `dotnet run` returns `307 Temporary Redirect`. -In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7320` and `https://localhost:7321` and redirects HTTP to HTTPS. +In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7320` and `https://localhost:7321` and redirects HTTP to HTTPS. The development certificate is new to your machine, so your browser treats it like a stranger until you introduce them. - Trust the .NET development certificate once on your machine: ```bash @@ -62,7 +62,7 @@ In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel **Symptom:** `dotnet new cleanmodelcontextprotocol` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. -Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). +Previews are fun, but the template only promises to work on a stable SDK. Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). - Check which SDKs are installed: ```bash @@ -74,7 +74,7 @@ Both `.template.config/template.json` and the generated `global.json` require a **Symptom:** Running `dotnet new cleanmodelcontextprotocol --include-auth` stops before writing any files and exits with code `102` (`Invalid option(s)` / missing mandatory option `--authority`). -When `--include-auth` is switched on, `--authority` is required so a generated solution never starts with a blank OAuth issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: +When `--include-auth` is switched on, `--authority` is required. Stopping at the door beats shipping a solution with a blank OAuth issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: ```bash dotnet new cleanmodelcontextprotocol --name WorksOnMyMachine.Movies \ @@ -89,13 +89,13 @@ See [Secure the server](/mcp/guides/secure-the-server/) for configuring OAuth 2. **Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. -Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. +Docker doesn't start itself, however much we'd like it to. Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. ## `SQLite Error 5: 'database is locked'` **Symptom:** Startup migration or a write tool fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. -`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. +`dotnet run` writes to `src/Presentation/movie-reviews.db`. SQLite lets plenty of readers share a file but only one writer at a time. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. - Stop the other process holding `src/Presentation/movie-reviews.db`. - If you want to wipe the local database and re-seed the sample data from scratch, stop the server, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the server again. diff --git a/src/content/docs/minimalapi/guides/run-locally.mdx b/src/content/docs/minimalapi/guides/run-locally.mdx index 2c1b9b7..1c486fd 100644 --- a/src/content/docs/minimalapi/guides/run-locally.mdx +++ b/src/content/docs/minimalapi/guides/run-locally.mdx @@ -17,7 +17,7 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data dotnet run --project ./src/Presentation ``` - `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7311](https://localhost:7311), and on `https://localhost:7311`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7311](https://localhost:7311), and on `http://localhost:7310`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. ```bash diff --git a/src/content/docs/minimalapi/reference/troubleshooting.mdx b/src/content/docs/minimalapi/reference/troubleshooting.mdx index 4d7347c..4975dd4 100644 --- a/src/content/docs/minimalapi/reference/troubleshooting.mdx +++ b/src/content/docs/minimalapi/reference/troubleshooting.mdx @@ -11,7 +11,7 @@ Most first-run problems aren't in the code. They're in the machine around it: a **Symptom:** `dotnet run` stops with `Failed to bind to address https://127.0.0.1:7311: address already in use`, or `docker compose up` fails with `Bind for 0.0.0.0:7310 failed: port is already allocated`. -Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Minimal API uses `7310` to `7319` (`7310` HTTP, `7311` HTTPS, `7312` Aspire dashboard, `7313` and `7314` OpenTelemetry Collector). A clash usually means another copy of this template is still running. +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Minimal API uses `7310` to `7319` (`7310` HTTP, `7311` HTTPS, `7312` Aspire dashboard, `7313` and `7314` OpenTelemetry Collector). A clash usually means an earlier copy of this template is still running somewhere, quietly hogging the port. - Check what's running in Docker and stop it: ```bash @@ -29,7 +29,7 @@ Each Lean Mean Clean template has its own block of ten ports so different templa **Symptom:** Your browser warns that `https://localhost:7311` is untrusted, `curl` fails with `SSL certificate problem: unable to get local issuer certificate`, or calling `http://localhost:7310` returns `307 Temporary Redirect` with an empty body. -In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7310` and `https://localhost:7311` and redirects HTTP to HTTPS. +In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7310` and `https://localhost:7311` and redirects HTTP to HTTPS. The development certificate is new to your machine, so your browser treats it like a stranger until you introduce them. - Trust the .NET development certificate once on your machine, then restart your browser: ```bash @@ -42,7 +42,7 @@ In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel **Symptom:** `dotnet new cleanminimalapi` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. -Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). +Previews are fun, but the template only promises to work on a stable SDK. Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). - Check which SDKs are installed: ```bash @@ -54,7 +54,7 @@ Both `.template.config/template.json` and the generated `global.json` require a **Symptom:** Running `dotnet new cleanminimalapi --include-auth` stops before writing any files and exits with code `102` (`Invalid option(s)` / missing mandatory option `--authority`). -When `--include-auth` is switched on, `--authority` is required so a generated solution never starts with a blank JWT issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: +When `--include-auth` is switched on, `--authority` is required. Stopping at the door beats shipping a solution with a blank JWT issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: ```bash dotnet new cleanminimalapi --name WorksOnMyMachine.Movies \ @@ -69,13 +69,13 @@ See [Secure the API](/minimalapi/guides/secure-the-api/) for configuring tokens **Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. -Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. +Docker doesn't start itself, however much we'd like it to. Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. ## `SQLite Error 5: 'database is locked'` **Symptom:** Startup migration or a write request fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. -`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. +`dotnet run` writes to `src/Presentation/movie-reviews.db`. SQLite lets plenty of readers share a file but only one writer at a time. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. - Stop the other process holding `src/Presentation/movie-reviews.db`. - If you want to wipe the local database and re-seed the sample data from scratch, stop the API, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the API again. @@ -85,7 +85,7 @@ Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` **Symptom:** Requests return `401 Unauthorized` when the solution was created with `--include-auth`. -Every `/api/*` route requires a valid JWT bearer token when authentication is included. +That's authentication doing its job. Every `/api/*` route requires a valid JWT bearer token when authentication is included. - In Scalar (`/scalar`), click **Authorize** at the top of the page and paste a bearer token issued by your `--authority`. - In `src/Presentation/Presentation.http`, uncomment the `@token` line at the top of the file, paste your token after it, and uncomment the `Authorization` header on each request. diff --git a/src/content/docs/webapi/guides/run-locally.mdx b/src/content/docs/webapi/guides/run-locally.mdx index d160f18..e580abf 100644 --- a/src/content/docs/webapi/guides/run-locally.mdx +++ b/src/content/docs/webapi/guides/run-locally.mdx @@ -17,7 +17,7 @@ There are two ready-made environments. `local` is for `dotnet run`: sample data dotnet run --project ./src/Presentation ``` - `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7341](https://localhost:7341), and on `https://localhost:7341`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. + `launchSettings.json` sets the environment to `local` and listens on [https://localhost:7341](https://localhost:7341), and on `http://localhost:7340`, which redirects to it. If your browser or `curl` doesn't trust the .NET development certificate yet, run `dotnet dev-certs https --trust` once. ```bash diff --git a/src/content/docs/webapi/reference/troubleshooting.mdx b/src/content/docs/webapi/reference/troubleshooting.mdx index 10dd6c9..a76bc90 100644 --- a/src/content/docs/webapi/reference/troubleshooting.mdx +++ b/src/content/docs/webapi/reference/troubleshooting.mdx @@ -11,7 +11,7 @@ Most first-run problems aren't in the controllers. They're in the machine around **Symptom:** `dotnet run` stops with `Failed to bind to address https://127.0.0.1:7341: address already in use`, or `docker compose up` fails with `Bind for 0.0.0.0:7340 failed: port is already allocated`. -Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Web API uses `7340` to `7349` (`7340` HTTP, `7341` HTTPS, `7342` Aspire dashboard, `7343` and `7344` OpenTelemetry Collector). A clash usually means another copy of this template is still running. +Each Lean Mean Clean template has its own block of ten ports so different templates don't step on each other. Clean Web API uses `7340` to `7349` (`7340` HTTP, `7341` HTTPS, `7342` Aspire dashboard, `7343` and `7344` OpenTelemetry Collector). A clash usually means an earlier copy of this template is still running somewhere, quietly hogging the port. - Check what's running in Docker and stop it: ```bash @@ -29,7 +29,7 @@ Each Lean Mean Clean template has its own block of ten ports so different templa **Symptom:** Your browser warns that `https://localhost:7341` is untrusted, `curl` fails with `SSL certificate problem: unable to get local issuer certificate`, or calling `http://localhost:7340` returns `307 Temporary Redirect` with an empty body. -In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7340` and `https://localhost:7341` and redirects HTTP to HTTPS. +In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel listens on both `http://localhost:7340` and `https://localhost:7341` and redirects HTTP to HTTPS. The development certificate is new to your machine, so your browser treats it like a stranger until you introduce them. - Trust the .NET development certificate once on your machine, then restart your browser: ```bash @@ -42,7 +42,7 @@ In the `local` environment (`dotnet run --project ./src/Presentation`), Kestrel **Symptom:** `dotnet new cleanwebapi` refuses to run because the SDK constraint `[10.0.100,)` isn't met, or `dotnet build` fails with `NETSDK1141` / `A compatible .NET SDK was not found`. -Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). +Previews are fun, but the template only promises to work on a stable SDK. Both `.template.config/template.json` and the generated `global.json` require a stable .NET 10 SDK (`10.0.100` or newer, rolling forward to the latest feature band with `allowPrerelease: false`). - Check which SDKs are installed: ```bash @@ -54,7 +54,7 @@ Both `.template.config/template.json` and the generated `global.json` require a **Symptom:** Running `dotnet new cleanwebapi --include-auth` stops before writing any files and exits with code `102` (`Invalid option(s)` / missing mandatory option `--authority`). -When `--include-auth` is switched on, `--authority` is required so a generated solution never starts with a blank JWT issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: +When `--include-auth` is switched on, `--authority` is required. Stopping at the door beats shipping a solution with a blank JWT issuer. Pass the authority (and optionally `--audience`) alongside `--include-auth`: ```bash dotnet new cleanwebapi --name WorksOnMyMachine.Movies \ @@ -69,13 +69,13 @@ See [Secure the API](/webapi/guides/secure-the-api/) for configuring tokens afte **Symptom:** `docker compose up -d --build` fails with `Cannot connect to the Docker daemon` or `error during connect`. -Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. +Docker doesn't start itself, however much we'd like it to. Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` to return cleanly before running `docker compose up -d --build`. You don't need Docker for `dotnet build`, `dotnet test` or `dotnet run --project ./src/Presentation`; the integration tests run against an in-memory SQLite database. ## `SQLite Error 5: 'database is locked'` **Symptom:** Startup migration or a write request fails with `Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 5: 'database is locked'`. -`dotnet run` writes to `src/Presentation/movie-reviews.db`. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. +`dotnet run` writes to `src/Presentation/movie-reviews.db`. SQLite lets plenty of readers share a file but only one writer at a time. A lock means another process is holding an open write transaction against that file, usually a second `dotnet run` terminal or a database viewer. - Stop the other process holding `src/Presentation/movie-reviews.db`. - If you want to wipe the local database and re-seed the sample data from scratch, stop the API, delete `src/Presentation/movie-reviews.db` (and any `-shm` or `-wal` files beside it), and start the API again. @@ -85,7 +85,7 @@ Start Docker Desktop (or the Docker service on Linux) and wait for `docker info` **Symptom:** Requests return `401 Unauthorized` when the solution was created with `--include-auth`. -Every `/api/*` controller action requires a valid JWT bearer token when authentication is included. +That's authentication doing its job. Every `/api/*` controller action requires a valid JWT bearer token when authentication is included. - In Scalar (`/scalar`), click **Authorize** at the top of the page and paste a bearer token issued by your `--authority`. - In `src/Presentation/Presentation.http`, uncomment the `@token` line at the top of the file, paste your token after it, and uncomment the `Authorization` header on each request.