{"record":{"id":"5b93f8dd6471d424","repo":"n8n-io/n8n","slug":"supabase-delete-failed-error-message","errorCode":null,"errorMessage":"Supabase delete failed: ${error.message}","messagePattern":"Supabase delete failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/@n8n/agents/src/vector-stores/supabase.ts","lineNumber":149,"sourceCode":"\t\t\tquery_embedding: vector,\n\t\t});\n\t\tconst filtered =\n\t\t\topts.filter && opts.filter.conditions.length > 0\n\t\t\t\t? applySupabaseFilter(rpcCall, opts.filter)\n\t\t\t\t: rpcCall;\n\n\t\tconst { data, error } = await filtered.limit(opts.topK);\n\t\tif (error) throw new Error(`Supabase query failed: ${error.message}`);\n\n\t\treturn (data ?? []).map(toQueryResult);\n\t}\n\n\tasync delete({ ids }: { ids: string[] }): Promise<void> {\n\t\tif (ids.length === 0) return;\n\n\t\tconst client = await this.getClient();\n\t\tconst { error } = await client.from(this.tableName).delete().in('id', ids);\n\t\tif (error) throw new Error(`Supabase delete failed: ${error.message}`);\n\t}\n\n\tclose(): void {\n\t\tthis.client = undefined;\n\t}\n\n\tprivate async getClient(): Promise<SupabaseClient> {\n\t\tif (!this.client) {\n\t\t\tconst { createClient } = await import('@supabase/supabase-js');\n\t\t\tthis.client = createClient(this.constructorOptions.url, this.constructorOptions.apiKey);\n\t\t}\n\t\treturn this.client;\n\t}\n}\n\nfunction toQueryResult(row: SupabaseMatchRow): VectorQueryResult {\n\treturn {\n\t\tid: String(row.id),","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/agents/src/vector-stores/supabase.ts#L131-L167","documentation":"Thrown by SupabaseVectorStore.delete when the PostgREST delete call returns a non-null error. Root causes, named in the appended message, are usually RLS denying DELETE, a missing table, an auth/connection failure, or (rarely) a constraint that blocks the delete. Empty id lists short-circuit before this call, so this only fires for a real delete attempt.","triggerScenarios":"RLS policy without a DELETE grant for the api key's role; tableName pointing at a non-existent table; service key wrong/expired; Supabase project paused; foreign-key ON DELETE RESTRICT blocking removal (surfaced through PostgREST).","commonSituations":"Anon key used for deletes (RLS blocks); RLS enabled but no DELETE policy; schema migration renaming the table; FK constraint preventing deletion of referenced rows.","solutions":["Inspect the appended message to classify (RLS vs missing relation vs constraint).","For RLS, use the service role key for trusted deletes or add a DELETE policy.","Confirm the table name is correct and the table exists.","For FK/constraint blocks, delete dependent rows first or adjust the constraint.","Retry transient/network errors."],"exampleFix":"// before — anon key, RLS blocks delete\nnew SupabaseVectorStore('docs', {\n  url, apiKey: process.env.SUPABASE_ANON_KEY, tableName: 'docs',\n});\n\n// after — service role key, or add a DELETE policy\nnew SupabaseVectorStore('docs', {\n  url, apiKey: process.env.SUPABASE_SERVICE_ROLE_KEY, tableName: 'docs',\n});","handlingStrategy":"retry","validationCode":"function assertSupabaseDeletable(opts: { url: string; apiKey: string; tableName: string }): void {\n  if (!opts.apiKey) throw new Error('Supabase apiKey missing (service role needed for deletes)');\n  if (!opts.tableName) throw new Error('Supabase tableName missing');\n  if (!/^https?:\\/\\/.+/.test(opts.url)) throw new Error('Supabase url missing/invalid');\n}\n\nassertSupabaseDeletable(opts);","typeGuard":null,"tryCatchPattern":"async function deleteWithRetry(store: SupabaseVectorStore, ids: string[], attempts = 3) {\n  if (ids.length === 0) return;\n  for (let i = 0; i < attempts; i++) {\n    try {\n      await store.deleteDocuments(ids);\n      return;\n    } catch (err) {\n      const msg = err instanceof Error ? err.message : '';\n      const transient = /network|timeout|fetch|ECONN|503|504|paused/i.test(msg);\n      if (!transient || i === attempts - 1) throw err;\n      await new Promise((r) => setTimeout(r, 2 ** i * 200));\n    }\n  }\n}","preventionTips":["Use the service role key for deletes (RLS typically blocks anon-role DELETE).","Add a DELETE RLS policy if you must use a non-service role.","Confirm the table exists and has no ON DELETE RESTRICT FKs blocking removal.","Retry only transient/network errors; escalate RLS/constraint errors immediately."],"tags":["supabase","database","network","rls","vector-store"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}