paperclipai/paperclip · error · Error

ctx.db.query cannot read schema "${ref.schema}"

Error message

ctx.db.query cannot read schema "${ref.schema}"

What it means

Schema isolation guard for runtime reads: a qualified reference in the SELECT targets a schema outside the plugin namespace and outside the whitelisted public core tables. Plugins can only read their own tables plus approved core tables; the cross-schema read is at fault.

Source

Thrown at server/src/services/plugin-database.ts:272

  }
  const statement = statements[0]!;
  assertNoBannedSql(statement);
  const normalized = normaliseSql(statement);
  if (!normalized.startsWith("select ") && !normalized.startsWith("with ")) {
    throw new Error("ctx.db.query only allows SELECT statements");
  }
  if (/\b(insert|update|delete|alter|create|drop|truncate)\b/.test(normalized)) {
    throw new Error("ctx.db.query cannot contain mutation or DDL keywords");
  }

  const allowedCoreReadTables = new Set(coreReadTables);
  for (const ref of extractQualifiedRefs(statement)) {
    if (ref.schema === namespace) continue;
    if (ref.schema === "public") {
      assertAllowedPublicRead(ref, allowedCoreReadTables);
      continue;
    }
    throw new Error(`ctx.db.query cannot read schema "${ref.schema}"`);
  }
}

export function validatePluginRuntimeExecute(query: string, namespace: string): void {
  const statements = splitSqlStatements(query);
  if (statements.length !== 1) {
    throw new Error("Plugin runtime SQL must contain exactly one statement");
  }
  const statement = statements[0]!;
  assertNoBannedSql(statement);
  const normalized = normaliseSql(statement);
  if (!/^(insert\s+into|update|delete\s+from)\b/.test(normalized)) {
    throw new Error("ctx.db.execute only allows INSERT, UPDATE, or DELETE");
  }
  if (/\b(alter|create|drop|truncate)\b/.test(normalized)) {
    throw new Error("ctx.db.execute cannot contain DDL keywords");
  }

View on GitHub (pinned to 120ae5428f)

Solutions

  1. Query only schemas the plugin is allowed to read (its own namespace or whitelisted tables).
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/services/plugin-database.ts:272 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@120ae5428f (2026-08-18). Data as JSON: /api/errors/3441b383908e1f40. Report an issue: GitHub.