{"record":{"id":"58233ed6129cc959","repo":"paperclipai/paperclip","slug":"plugin-sql-references-schema-ref-schema-outsi","errorCode":null,"errorMessage":"Plugin SQL references schema \"${ref.schema}\" outside namespace \"${namespace}\"","messagePattern":"Plugin SQL references schema \"(.+?)\" outside namespace \"(.+?)\"","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"server/src/services/plugin-database.ts","lineNumber":242,"sourceCode":"    \"create view\",\n    \"drop table\",\n    \"into\",\n    \"truncate table\",\n    \"update\",\n  ]);\n  const hasQualifiedObjectRef = refs.some((ref) => objectRefKeywords.has(ref.keyword));\n  if (!hasQualifiedObjectRef && !normalized.startsWith(\"comment \")) {\n    throw new Error(\"Plugin migration objects must use fully qualified schema names\");\n  }\n\n  const allowedCoreReadTables = new Set(coreReadTables);\n  for (const ref of refs) {\n    if (ref.schema === namespace) continue;\n    if (ref.schema === \"public\") {\n      assertAllowedPublicRead(ref, allowedCoreReadTables);\n      continue;\n    }\n    throw new Error(`Plugin SQL references schema \"${ref.schema}\" outside namespace \"${namespace}\"`);\n  }\n}\n\nexport function validatePluginRuntimeQuery(\n  query: string,\n  namespace: string,\n  coreReadTables: readonly PluginDatabaseCoreReadTable[] = [],\n): void {\n  const statements = splitSqlStatements(query);\n  if (statements.length !== 1) {\n    throw new Error(\"Plugin runtime SQL must contain exactly one statement\");\n  }\n  const statement = statements[0]!;\n  assertNoBannedSql(statement);\n  const normalized = normaliseSql(statement);\n  if (!normalized.startsWith(\"select \") && !normalized.startsWith(\"with \")) {\n    throw new Error(\"ctx.db.query only allows SELECT statements\");\n  }","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/server/src/services/plugin-database.ts#L224-L260","documentation":"Namespace containment guard: a qualified reference in the migration targets a schema other than the plugin's derived namespace and other than public. Plugins may only touch their own schema (plus whitelisted public reads); the statement referencing the foreign schema is at fault.","triggerScenarios":"Thrown at server/src/services/plugin-database.ts:242 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Change the SQL to reference only objects inside the plugin's namespace schema."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}