# Troubleshooting

## Signed out after a project database change

When an Auth, Data API, or schema request returns
`session_database_changed`, the current tokens were issued for the project's
previous database. This is a terminal session boundary, not a retryable network
failure. The SDK removes the saved session and emits `SIGNED_OUT`; prompt the
user to sign in again and do not restore the old tokens from another cache.

If the error code is different, do not assume the database changed. In
particular, ordinary `403` policy errors, network failures, and `5xx` responses
do not clear a valid session.

This document covers common integration, contract, security, and release-readiness failures for `@tidbcloud/auth-js`.

The package is TiDB-native and Supabase-like. It is not a `supabase-js`, PostgREST, PostgreSQL, or PostgreSQL RLS compatibility layer.

## Package Is Not Release Ready

Symptom:

- the package exists locally, but a release should not be published or consumed
- release automation reports missing gates

Meaning:

- release readiness is evidence-based
- every gate in `docs/release-checklist.md` must pass for the release candidate

Fix:

```sh
cd tidbcloud-auth-js
npm run sync:fixtures
npm run typecheck
npm run build
npm test
npm run test:contracts
npm run test:types
npm run test:security
npm run test:exports
npm run test:bundle
npm run pack:dry-run
```

Also run the service fixture baseline from the repository root:

```sh
cd tidbcloud-auth
GOCACHE=/private/tmp/supabase-like-go-build-cache go test ./internal/tidbrest -run 'TestSDKRequestFixturesCoverPositiveContract|TestNegativeRequestFixturesReturnStableErrors|TestCompatibilityRequestFixturesCoverStableRoutesErrorsAndAuthHeaders|TestOpenAPISDKSecurityModeFixtures' -count=1 -v
```

## `bearer_requires_client_key`

Symptom:

```http
Authorization: Bearer <user-jwt>
```

returns an auth error.

Meaning:

- the Data API requires a client key even when a user JWT is present
- bearer-only requests are invalid by service contract

Fix:

```http
apikey: <client-key>
Authorization: Bearer <user-jwt>
```

In SDK code, configure both the public client key and the access-token provider:

```ts
const tidb = createClient<Database>(url, clientKey, {
  auth: {
    getAccessToken: async () => userJwt
  }
});
```

## `invalid_client_key`

Meaning:

- the request did not include a valid public client key
- the key is malformed, expired, revoked, or from the wrong project

Fix:

- confirm the application uses the public client key, not a user JWT as the client key
- confirm the key belongs to the target TiDB Cloud project
- confirm the key is sent as `apikey`
- rotate leaked or uncertain keys before retrying

## OAuth Redirect Or Provider Errors

Common symptoms:

- `unsupported_oauth_provider`
- `unsupported_identity_provider`
- `invalid_redirect_uri`
- `oauth_state_required`
- `oauth_provider_required`
- `oauth_redirect_to_required`
- `invalid_oauth_state`

Meaning:

- only GitHub and Google are exposed by the application SDK
- the provider may be disabled in the project Auth provider configuration
- `redirectTo` is not in the project's redirect allowlist
- the callback was handled without the saved PKCE verifier/state
- the wrong project public client key was used for start or callback exchange

Fix:

```ts
await tidb.auth.signInWithOAuth({
  provider: 'google',
  options: {
    redirectTo: 'https://app.example.test/auth/callback',
    skipBrowserRedirect: true
  }
});
```

Then exchange the callback code with the same app URL and project client key:

```ts
await tidb.auth.exchangeCodeForSession(code, {
  provider: 'google',
  state,
  redirectTo: 'https://app.example.test/auth/callback'
});
```

Do not persist provider client secrets in application code. OAuth provider secrets belong to the service/control-plane configuration, not the frontend SDK.

## `table_not_published`

Meaning:

- the table may exist in TiDB, but it is not published as an application-visible Data API resource

Fix:

- publish the table through the controlled service workflow
- expose only the intended columns and actions
- regenerate application types from published metadata

Do not work around this by adding raw SQL, admin routes, or direct database introspection to the SDK.

## `table_not_found`

Meaning:

- the request targets an unknown table path or an unpublished table name

Fix:

- check table name spelling
- check the path style: the default canonical `/table/<table>` (legacy `/rest/v1/<table>` is retired by the backend and returns HTTP 501)
- check generated `Database` types
- check published metadata such as `/schema`

## `mutation_filter_required`

Symptom:

```ts
tidb.from('tasks').update({ status: 'done' }).toRequest();
tidb.from('tasks').delete().toRequest();
```

throws locally before fetch.

Meaning:

- broad `PATCH` and `DELETE` operations are intentionally blocked

Fix:

```ts
await tidb.from('tasks').update({ status: 'done' }).eq('id', 1);
await tidb.from('tasks').delete().eq('id', 1);
```

## `unsupported_operation`

Meaning:

- the request attempted a capability outside the public Data API boundary

Common causes:

- `/sql`
- `/query`
- `/rpc/...`
- `/grant`
- `/revoke`
- `/admin`
- `/system`
- `/mcp`
- `/ui`
- `/console`
- schema mutation through `/schema`
- PostgreSQL `RETURNING`
- `Prefer: return=representation`
- `Prefer: tx=rollback`

Fix:

- use published table Data API builders
- move business logic to controlled server-side application code
- use admin/migration tooling outside this public SDK for schema changes
- document unsupported PostgreSQL-specific behavior instead of emulating it

## Capability Or Contract Mismatch

Symptoms:

- a capability is listed as `unsupported` or `deferred`
- `tidb.schema.checkContractVersion()` returns `compatible: false`
- `isUnsupportedCapability()` reports that a feature should not be called

Meaning:

- the SDK is reading the published `/doc` capability matrix
- unsupported and deferred capabilities are descriptive only, not hidden API switches

Fix:

```ts
const capabilities = await tidb.schema.getCapabilities();

if (isUnsupportedCapability(capabilities, 'rpc')) {
  // Do not call or emulate RPC through the public SDK.
}
```

Use published table APIs or controlled server-side code instead of adding raw SQL, DDL, admin, or procedure routes to the SDK.

## `data_action_not_allowed_by_schema`

Meaning:

- local published schema metadata says the action is not allowed for this resource
- the request was stopped before fetch as a developer-experience guard

Fix:

- check `published_resources[].allowed_actions`
- regenerate types from the current published schema
- remember that the service still makes the final policy decision

## `data_column_not_allowed_by_schema`

Meaning:

- local published schema metadata says one or more selected, filtered, ordered, inserted, or updated columns are not allowed

Fix:

- check `published_resources[].allowed_columns`
- remove unpublished columns from the builder call
- publish the column through the controlled service workflow if it should be application-visible

## `unsupported_select_grammar`

Symptom:

```ts
tidb.from('tasks').select('id,comments(*)');
tidb.from('tasks').select('status.count()');
```

Meaning:

- embedded relationship and aggregate select grammar are not part of the TiDB-native public SDK contract

Fix:

- query a published resource directly
- create an explicit server-side application endpoint for composed views
- use supported filters and pagination

## Network Or Timeout Errors

Meaning:

- no response was received
- fetch is unavailable in the runtime
- the request timed out
- a retryable `GET` exhausted retries

Fix:

- provide `global.fetch` when the runtime does not expose `fetch`
- verify the service URL and network path
- tune timeout and retry policy where exposed by the request pipeline
- do not rely on automatic replay for mutations

## Bundle Contains Service Key Text

Meaning:

- a service secret may have entered application code
- application code may still depend on the removed Public Data/Schema Service Key path

Fix:

- remove service keys from browser environment variables
- use a Client Key for Public Data/Schema requests and add a user JWT only when end-user policy evaluation requires it
- do not send `X-Service-Key`; no SDK runtime entry supports it for Public Data/Schema APIs
- run security and bundle tests

```sh
cd tidbcloud-auth-js
npm run test:security
npm run test:bundle
```

## Logs Or Errors Contain Secrets

Meaning:

- logger, hook, telemetry, or error serialization redaction failed

Secrets that must be redacted:

- `apikey`
- `Authorization`
- `X-Service-Key`
- JWTs
- refresh tokens
- cookies
- passwords
- DSNs
- secret-bearing request or response bodies

Fix:

- use SDK-provided normalized errors and redaction utilities
- do not log raw request headers or raw bodies
- run security tests before release

## Contract Fixtures Are Out Of Sync

Symptom:

- contract tests fail with generated fixture mismatch
- checksum lines differ

Meaning:

- service fixture source of truth changed under `tidbcloud-auth/internal/tidbrest/testdata/sdk_requests/`
- SDK generated fixture snapshots were not refreshed

Fix:

```sh
cd tidbcloud-auth-js
npm run sync:fixtures
npm run test:contracts
```

Then review the fixture diff. A fixture change may require API docs, migration notes, type behavior, and release gate updates.

## Type Errors For Tables Or Columns

Meaning:

- the `Database` type does not match published metadata
- application code references unpublished tables or columns

Fix:

- regenerate or update the `Database` type from published metadata
- avoid hand-adding private tables to application-visible types
- check whether the table or column is intentionally unpublished

## Dry Pack Omits Required Docs

Symptom:

- `npm run pack:dry-run` does not list README, security docs, migration docs, troubleshooting docs, API reference, or release checklist

Meaning:

- package tarball contents do not match production documentation requirements

Fix:

- update release packaging configuration in a separate scoped change
- rerun `npm run pack:dry-run`
- do not publish until the tarball allowlist gate passes
