tursodatabase/turso · error · DatabaseError

Unexpected describe response

Error message

Unexpected describe response

What it means

DatabaseError thrown when the pipeline response to a describe request has an unexpected shape: results is missing or empty, or the first result is neither an error nor a describe result carrying a payload. Unlike a describe error this signals a protocol or version mismatch — the server answered 200 but not with the structure the client expects.

Source

Thrown at serverless/javascript/src/session.ts:205

    this.baton = response.baton;
    if (response.base_url) {
      this.baseUrl = normalizeUrl(response.base_url);
    }
    this.updateAutocommit(response);

    // Check for errors in the response
    if (response.results && response.results[0]) {
      const result = response.results[0];
      if (result.type === "error") {
        throw new DatabaseError(result.error?.message || 'Describe execution failed', result.error?.code);
      }

      if (result.response?.type === "describe" && result.response.result) {
        return result.response.result as DescribeResult;
      }
    }

    throw new DatabaseError('Unexpected describe response');
  }

  /**
   * Execute a SQL statement and return all results.
   *
   * @param sql - The SQL statement to execute
   * @param args - Optional array of parameter values or object with named parameters
   * @param safeIntegers - Whether to return integers as BigInt
   * @returns Promise resolving to the complete result set
   */
  async execute(sql: string, args: any[] | Record<string, any> = [], safeIntegers: boolean = false, queryOptions?: QueryOptions): Promise<any> {
    const { response, entries } = await this.executeRaw(sql, args, queryOptions);
    const result = await this.processCursorEntries(entries, safeIntegers);
    return result;
  }

  /**
   * A trailing batch step gated on `is_autocommit`, appended to every cursor

View on GitHub (pinned to bad083fafb)

Solutions

  1. Confirm the URL targets a current Turso SQL-over-HTTP v3 endpoint (curl the /v3/pipeline describe request and inspect the JSON shape)
  2. Align versions: update the server or the client so both speak the same protocol
  3. Fix test mocks to return a well-formed PipelineResponse whose first result is { type: 'ok', response: { type: 'describe', result: {...} } }

Example fix

// before — URL returns 200 but is not a v3 pipeline server
const db = connect({ url: "https://api.example.com" });
await db.prepare("SELECT 1"); // Unexpected describe response

// after
const db = connect({ url: "https://my-db-my-org.turso.io" });
await db.prepare("SELECT 1");
Defensive patterns

Strategy: try-catch

Type guard

const isDatabaseError = (e: unknown): e is Error & { code?: string } =>
  e instanceof Error && e.name === "DatabaseError";

Try / catch

try {
  await db.prepare("SELECT 1"); // cheap protocol smoke test
} catch (e) {
  if (e instanceof Error && e.message === "Unexpected describe response") {
    // endpoint is not speaking v3 pipeline: verify URL and server version,
    // do not retry blindly — it will fail identically
    throw new Error("database endpoint is not a Turso v3 pipeline server");
  }
  throw e;
}

Prevention

When it happens

Trigger: Pointing the client at a server that does not implement the v3 pipeline describe request; test mocks or proxies returning arbitrary 200 JSON; an intermediary rewriting the response body between server and client.

Common situations: Self-hosted sqld/hrana server versions older than the describe support; URL pointing at a different product's endpoint that still returns 200 JSON; shallow fetch stubs in unit tests that return generic fixtures for every request.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/f0a95927e04ba2e1. Report an issue: GitHub.