TL;DR: Your DATABASE_URL does not start with `postgresql://` or `postgres://`. Copy the full connection string from your database provider, including the scheme prefix, and set it as DATABASE_URL. The value is malformed, not missing.

```text
error: Error validating datasource `db`: the URL must start with the protocol `postgresql://` or `postgres://`.
```

## Steps

1. Print the value Prisma sees (mask the password when sharing):
   ```bash
   node -e "const u=new URL(process.env.DATABASE_URL); console.log(u.protocol+'//'+u.host+u.pathname)"
   ```
   Expected: `postgresql://YOUR_HOST:5432/mydb`. If node throws 'Invalid URL', the value is malformed.

2. Fix the common shapes:
   - Missing scheme: `YOUR_HOST:5432/mydb` becomes `postgresql://YOUR_HOST:5432/mydb`
   - Wrong provider: a `mysql://` URL against a `provider = "postgresql"` schema fails; match the scheme to the provider
   - SQLite path in a Postgres schema: `file:./dev.db` fails; point at a real Postgres or change the provider
   Expected: the value now parses as a URL with the right protocol.

3. Set it where the failing command runs (CI secret, container env, or local shell) and re-run:
   ```bash
   npx prisma validate
   ```
   Expected: `The schema is valid` instead of the P1012 protocol error.

## When to use
- The exact message is the P1012 protocol error on validate, generate, migrate, or db push
- The provider in the schema is postgresql but the URL looks like anything else

## When not to use
- `Environment variable not found: DATABASE_URL`: the variable is missing entirely, a different fix
- P1000/P1001: the URL parses fine but the server rejects you or is unreachable

## Compatibility
Prisma 2.x through 7.x. The message text is the same across versions.

### Variant phrasing: `the URL must start with the protocol `file:``
Same shape, SQLite provider. Your URL must start with `file:` (for example `file:./dev.db`) when the provider is sqlite.

### Variant phrasing: protocol error after switching providers
Changing `provider` in the schema without changing the URL is the classic trigger. Update both together.

## Why it happens
Prisma validates the datasource URL against the provider before connecting. A URL with no scheme, the wrong scheme, or a leftover from another provider fails this check immediately, which is why the fix is always in the value, never in Prisma itself.

## Edge cases
- Quoting: some shells strip characters from unquoted URLs; quote the assignment.
- Some providers issue `postgres://` and some `postgresql://`; Prisma accepts both for the postgresql provider.
- On Prisma 7 the same check runs against `prisma.config.ts` datasource url; fix the value there too.