[{"data":1,"prerenderedAt":1325},["ShallowReactive",2],{"blog-uk-invalid-input-syntax-for-type-uuid":3,"blog-index-uk":795},{"id":4,"title":5,"body":6,"category":752,"cover":753,"coverAlt":754,"description":755,"draft":756,"extension":757,"faq":758,"image":774,"keywords":775,"meta":784,"navigation":785,"ogTitle":5,"path":786,"published":787,"seo":788,"stem":789,"tldr":790,"updated":787,"__hash__":794},"blog_uk\u002Fblog\u002Finvalid-input-syntax-for-type-uuid.md","Supabase \"invalid input syntax for type uuid\": що в лапках",{"type":7,"value":8,"toc":740},"minimark",[9,13,24,31,37,42,49,82,85,188,192,195,325,328,332,338,383,393,399,402,453,457,466,474,483,504,510,513,518,522,525,538,554,559,563,566,603,611,615,618,627,647,656,674,678,733],[10,11,12],"p",{},"Ви відкриваєте панель свого застосунку, і список проєктів якусь мить порожній, а\nпотім заповнюється. Або лишається порожнім. Так чи так, у консолі браузера\nчервоний рядок, а запит за ним відповів ось цим:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","{\n  \"code\": \"22P02\",\n  \"details\": null,\n  \"hint\": null,\n  \"message\": \"invalid input syntax for type uuid: \\\"undefined\\\"\"\n}\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26,27,30],{},"Supabase \"invalid input syntax for type uuid\" означає, що Postgres отримав\nзначення, яке не є uuid, для колонки, де зберігаються лише uuid, і відхилив увесь\nзапит. Те, що в лапках, і є тим, що надіслав ваш застосунок. Тут це слово\n",[21,28,29],{},"undefined",": запит пішов раніше, ніж з'явився потрібний йому id.",[10,32,33,34,36],{},"Швидкі виправлення, які ходять для цієї помилки, такі: змінити колонку на ",[21,35,19],{},"\nабо перетворити значення. Обидва прибирають повідомлення. Жодне не дає запиту\nйого id, тож сторінка далі просить не те і перестає вам про це казати.",[38,39,41],"h2",{"id":40},"що-означає-invalid-input-syntax-for-type-uuid","Що означає \"invalid input syntax for type uuid\"?",[10,43,44,45,48],{},"Це означає, що значення на шляху до колонки ",[21,46,47],{},"uuid"," було записане не так, як\nзаписують uuid, тож Postgres зупинився, нічого не виконавши. Жодного рядка не\nпрочитано і жодного не змінено.",[10,50,51,52,55,56,59,60,55,63,66,67,70,71,74,75,81],{},"uuid має одну сталу форму: 32 символи від ",[21,53,54],{},"0"," до ",[21,57,58],{},"9"," і від ",[21,61,62],{},"a",[21,64,65],{},"f",",\nзаписані групами по 8, 4, 4, 4 і 12, наприклад\n",[21,68,69],{},"3f2b8c1e-9a4d-4e7b-b1c2-5d6e7f8a9b0c",". Supabase дає такий id кожному\nкористувачу, що увійшов, а колонка, яка записує, чий рядок чий, як-от ",[21,72,73],{},"user_id",",\nзберігає таке саме значення.\n",[62,76,80],{"href":77,"rel":78},"https:\u002F\u002Fgithub.com\u002Fpostgres\u002Fpostgres\u002Fblob\u002Fmaster\u002Fsrc\u002Fbackend\u002Futils\u002Fadt\u002Fuuid.c",[79],"nofollow","Читач Postgres для цього типу","\nприймає \"a series of 32 hexadecimal digits with an optional dash after each group\nof 4 hexadecimal digits, and optionally surrounded by {}\". Усе інше закінчується\nцим повідомленням, і вхідне значення цитується.",[10,83,84],{},"Уявіть колонку як сортувальну машину, що читає лише один вид етикетки: код із\nцих п'яти груп. Ваш застосунок поклав на стрічку посилку, на якій там, де має\nбути код, написане слово. Машина зупинила стрічку і прочитала вам це слово.",[86,87,88,104],"table",{},[89,90,91],"thead",{},[92,93,94,98,101],"tr",{},[95,96,97],"th",{},"Поле",[95,99,100],{},"Приклад",[95,102,103],{},"Що воно вам каже",[105,106,107,131,146,165],"tbody",{},[92,108,109,114,119],{},[110,111,112],"td",{},[21,113,21],{},[110,115,116],{},[21,117,118],{},"22P02",[110,120,121,122,127,128],{},"Код Postgres для цієї помилки, у ",[62,123,126],{"href":124,"rel":125},"https:\u002F\u002Fgithub.com\u002Fpostgres\u002Fpostgres\u002Fblob\u002Fmaster\u002Fsrc\u002Fbackend\u002Futils\u002Ferrcodes.txt",[79],"його списку кодів"," він називається ",[21,129,130],{},"invalid_text_representation",[92,132,133,138,143],{},[110,134,135],{},[21,136,137],{},"message",[110,139,140],{},[21,141,142],{},"invalid input syntax for type uuid: \"undefined\"",[110,144,145],{},"Тип, на який чекав Postgres, і точне значення, яке він отримав",[92,147,148,157,162],{},[110,149,150,153,154],{},[21,151,152],{},"details",", ",[21,155,156],{},"hint",[110,158,159],{},[21,160,161],{},"null",[110,163,164],{},"Більше нічого Postgres для цієї помилки не додає",[92,166,167,170,175],{},[110,168,169],{},"Статус HTTP",[110,171,172],{},[21,173,174],{},"400 Bad Request",[110,176,177,178,181,182,187],{},"Так PostgREST, частина Supabase, яка перетворює виклики ",[21,179,180],{},"supabase.from(...)"," на SQL, відповідає на будь-який код без власного статусу (",[62,183,186],{"href":184,"rel":185},"https:\u002F\u002Fgithub.com\u002FPostgREST\u002Fpostgrest\u002Fblob\u002Fmain\u002Fsrc\u002Flibrary\u002FPostgREST\u002FError.hs",[79],"його код",")",[38,189,191],{"id":190},"прочитайте-що-стоїть-у-лапках","Прочитайте, що стоїть у лапках",[10,193,194],{},"Найкорисніша частина повідомлення стоїть у лапках. Там саме те, що дійшло до\nбази, і кожна форма цього значення вказує на інший рядок вашого застосунку.",[86,196,197,210],{},[89,198,199],{},[92,200,201,204,207],{},[95,202,203],{},"У лапках",[95,205,206],{},"Що надіслав ваш застосунок",[95,208,209],{},"Де шукати",[105,211,212,225,242,269,289,306],{},[92,213,214,219,222],{},[110,215,216],{},[21,217,218],{},"\"undefined\"",[110,220,221],{},"змінну, яка ще не мала значення",[110,223,224],{},"запит, що пішов раніше, ніж завантажилися користувач або id сторінки; два наступні розділи",[92,226,227,232,235],{},[110,228,229],{},[21,230,231],{},"\"\"",[110,233,234],{},"порожній рядок",[110,236,237,238,241],{},"значення, яке в стані вашого застосунку починається з ",[21,239,240],{},"''",", або порожнє поле форми",[92,243,244,249,257],{},[110,245,246],{},[21,247,248],{},"\"null\"",[110,250,251,253,254],{},[21,252,161],{},", переданий у ",[21,255,256],{},".eq()",[110,258,259,261,262,264,265,268],{},[21,260,256],{}," теж записує ",[21,263,161],{}," як слово. Щоб знайти рядки, де колонка порожня, документація supabase-js каже \"use ",[21,266,267],{},".is()"," instead\"",[92,270,271,276,279],{},[110,272,273],{},[21,274,275],{},"\"[object Object]\"",[110,277,278],{},"цілий об'єкт на місці його id",[110,280,281,284,285,288],{},[21,282,283],{},"user"," замість ",[21,286,287],{},"user.id",". JavaScript пише цей текст для будь-якого об'єкта, перетвореного на рядок",[92,290,291,296,299],{},[110,292,293],{},[21,294,295],{},"\"user_…\"",[110,297,298],{},"id від іншого сервісу входу, не від Supabase",[110,300,301,302,305],{},"id у Clerk починаються з ",[21,303,304],{},"user_"," і не є uuid. Цей випадок розібрано в розділі про зміну колонки",[92,307,308,311,314],{},[110,309,310],{},"число або назва",[110,312,313],{},"частину адреси сторінки",[110,315,316,317,320,321,324],{},"URL на кшталт ",[21,318,319],{},"\u002Fprojects\u002F42"," чи ",[21,322,323],{},"\u002Fprojects\u002Fmy-first-app",", прочитаний як id",[10,326,327],{},"Якщо помилка з'являється на кожному візиті, шукайте назву, під якою нічого немає.\nЯкщо лише під час першого відмальовування сторінки, шукайте значення, яке ще не\nвстигло завантажитися.",[38,329,331],{"id":330},"чому-supabase-js-надсилає-слово-undefined","Чому supabase-js надсилає слово undefined?",[10,333,334,335,337],{},"Бо він записує кожен фільтр як текст в адресу запиту, а JavaScript записує\nвідсутнє значення словом ",[21,336,29],{},".",[10,339,340,341,344,345,348,349,354,355,358,359,362,363,366,367,372,373,375,376,379,380,382],{},"Виклик на кшталт ",[21,342,343],{},".eq('user_id', user?.id)"," стає ",[21,346,347],{},"?user_id=eq.",", а далі значення.\n",[62,350,353],{"href":351,"rel":352},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-js\u002Fblob\u002Fmaster\u002Fpackages\u002Fcore\u002Fpostgrest-js\u002Fsrc\u002FPostgrestFilterBuilder.ts",[79],"Вихідний код бібліотеки","\nбудує це з шаблону ",[21,356,357],{},"`eq.${value}`",", а коментар нижче в тому самому файлі\nкаже, що це робить із відсутнім значенням: воно \"show up as\n",[21,360,361],{},"?column=eq.undefined","\". PostgREST читає все після ",[21,364,365],{},"eq."," як звичайний текст, а\n",[62,368,371],{"href":369,"rel":370},"https:\u002F\u002Fgithub.com\u002FPostgREST\u002Fpostgrest\u002Fblob\u002Fmain\u002Fsrc\u002Flibrary\u002FPostgREST\u002FApiRequest\u002FQueryParams.hs",[79],"його парсер","\nвважає ",[21,374,161],{}," ключовим словом лише після ",[21,377,378],{},"is.",". Postgres отримує дев'ять літер\nслова ",[21,381,29],{}," і намагається прочитати їх як uuid.",[10,384,385,388,389,337],{},[21,386,387],{},".rpc()"," поводиться навпаки. Його аргументи їдуть як JSON, а JSON повністю\nвикидає значення undefined, тож виклик функції втрачає аргумент замість того, щоб\nнадіслати слово, і Supabase відповідає\n",[62,390,392],{"href":391},"\u002Fblog\u002Fsupabase-function-not-found","Could not find the function",[394,395],"diagram",{"alt":396,"caption":397,"src":398},"Картка фільтра з user_id і бурштиновою клітинкою, в якій стоїть undefined. Стрілка веде до смужки запиту, що закінчується на eq.undefined, далі до слова в лапках на бирці над полем коду з п'яти клітинок, куди воно не влазить, і вниз до таблички з 22P02 і 400.","supabase-js вставляє значення фільтра в запит як текст. Відсутнє значення приходить словом undefined, і колонка uuid його відхиляє.","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fundefined-becomes-a-word-1600x560.png",[10,400,401],{},"У застосунку на React шукайте відсутнє значення у трьох місцях:",[403,404,405,427,447],"ul",{},[406,407,408,412,413,416,417,419,420,423,424,426],"li",{},[409,410,411],"strong",{},"Користувач ще не завантажився."," Supabase читає сесію асинхронно\n(",[21,414,415],{},"await supabase.auth.getSession()","), тож під час першого відмальовування\nсторінки ",[21,418,283],{}," у стані ще порожній, а ",[21,421,422],{},"user?.id"," дорівнює ",[21,425,29],{},". Запит,\nзапущений на цьому першому відмальовуванні, це й надсилає.",[406,428,429,432,433,436,437,440,441,444,445,337],{},[409,430,431],{},"id має іншу назву."," Маршрут, записаний як ",[21,434,435],{},"\u002Fprojects\u002F:projectId",", кладе\nзначення під ",[21,438,439],{},"projectId",", а сторінка, яка читає ",[21,442,443],{},"id",", на кожному візиті\nотримує ",[21,446,29],{},[406,448,449,452],{},[409,450,451],{},"id береться з даних, які ще в дорозі."," id з результату іншого запиту,\nпрочитаний раніше, ніж той запит відповів.",[38,454,456],{"id":455},"притримайте-запит-доки-не-зявиться-id","Притримайте запит, доки не з'явиться id",[10,458,459,460,462,463,465],{},"Перевірте id перед викликом і дайте сторінці показувати стан завантаження, доки\nid не прийде. Для ",[21,461,218],{}," і ",[21,464,231],{}," це і є все виправлення.",[14,467,472],{"className":468,"code":470,"language":471,"meta":23},[469],"language-js","useEffect(() => {\n  if (!user?.id) return\n\n  supabase\n    .from('projects')\n    .select('*')\n    .eq('user_id', user.id)\n    .then(({ data, error }) => {\n      if (!error) setProjects(data)\n    })\n}, [user?.id])\n","js",[21,473,470],{"__ignoreMap":23},[10,475,476,479,480,482],{},[21,477,478],{},"return"," нічого не надсилає, поки id немає, а ",[21,481,422],{}," у списку наприкінці\nзнову запускає ефект, щойно id з'являється. На сортувальній машині це означає\nчекати, доки код опиниться на етикетці, і лише тоді класти посилку на стрічку.",[10,484,485,486,489,490,493,494,499,500,503],{},"Якщо ваш застосунок завантажує дані через TanStack Query (хук ",[21,487,488],{},"useQuery","), його\nопція ",[21,491,492],{},"enabled"," працює як той самий запобіжник.\n",[62,495,498],{"href":496,"rel":497},"https:\u002F\u002Ftanstack.com\u002Fquery\u002Flatest\u002Fdocs\u002Fframework\u002Freact\u002Fguides\u002Fdependent-queries",[79],"Його посібник про залежні запити","\nставить ",[21,501,502],{},"enabled: !!userId"," з приміткою \"The query will not execute until the\nuserId exists\".",[14,505,508],{"className":506,"code":507,"language":471,"meta":23},[469],"const { data: projects } = useQuery({\n  queryKey: ['projects', user?.id],\n  queryFn: async () => {\n    const { data, error } = await supabase\n      .from('projects')\n      .select('*')\n      .eq('user_id', user.id)\n    if (error) throw error\n    return data\n  },\n  enabled: !!user?.id,\n})\n",[21,509,507],{"__ignoreMap":23},[10,511,512],{},"Якщо ви будуєте промптами, попросіть про це одним реченням. Залиште його\nанглійською, мовою, якою ці інструменти міркують: \"Don't run the projects query\nuntil user.id exists, and show the loading state until then.\"",[394,514],{"alt":515,"caption":516,"src":517},"Два ряди, у кожному два пронумеровані відмальовування сторінки. У верхньому ряду перше відмальовування має порожній id, і його запит закінчується бурштиновою табличкою 22P02; друге має id і закінчується галочкою. У нижньому ряду з позначкою if (!id) return перше відмальовування зупиняється на знаку паузи й нічого не надсилає, і лише друге надсилає запит, який закінчується галочкою.","Без перевірки перше відмальовування надсилає запит без id. З нею перше відмальовування чекає, і надсилається лише той запит, що працює.","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fthe-guard-holds-the-query-1600x640.png",[38,519,521],{"id":520},"чи-варто-змінити-колонку-на-text","Чи варто змінити колонку на text?",[10,523,524],{},"Ні, хіба що id, які ви зберігаєте, взагалі не uuid. Зміна колонки чи її\nперетворення на text у запиті прибирає перевірку, яка підняла помилку, і лишає\nвідсутній id там, де він був.",[10,526,527,528,531,532,534,535,537],{},"Простежте той самий запит після зміни. ",[21,529,530],{},"user_id=eq.undefined"," тепер стає\nзаконним питанням, тож Postgres порівнює слово ",[21,533,29],{}," з кожним id у колонці, не\nзнаходить збігу і повертає порожній список. Ваша сторінка показує \"Поки немає\nпроєктів\" людині, в якої їх десять, і в консолі немає нічого, що б це пояснило.\nПід час запису все йде далі: рядок зберігається з ",[21,536,29],{}," там, де має бути id\nвласника, і запит від справжнього власника його ніколи не знаходить. На\nсортувальній машині це означає вимкнути зчитувач етикеток. Посилка проходить, не\nзбігається з жодною адресою і ніколи не доходить.",[10,539,540,541,543,544,549,550,553],{},"Змінювати треба саме колонку лише в одному випадку: у рядку ",[21,542,295],{}," таблиці\nвище. id у Clerk текстові, і\n",[62,545,548],{"href":546,"rel":547},"https:\u002F\u002Fclerk.com\u002Fdocs\u002Fguides\u002Fdevelopment\u002Fintegrations\u002Fdatabases\u002Fsupabase",[79],"власний посібник Clerk для Supabase","\nстворює колонку як ",[21,551,552],{},"user_id text not null default auth.jwt()->>'sub'",". Це інша\nпроблема: таблицю зробили під id від Supabase, а вона отримує id іншого сервісу.",[394,555],{"alt":556,"caption":557,"src":558},"Той самий запит, user_id=eq.undefined, до двох колонок. Колонка з позначкою uuid відхиляє його бурштиновою табличкою з 22P02 і 400. Колонка з позначкою text порівнює слово з кожним рядком, не знаходить жодного і повертає порожній список, бурштинову пунктирну рамку поруч зі звичайним 200.","Колонка uuid відхиляє слово і каже про це. Колонка text його приймає, не знаходить жодного рядка і віддає вашій сторінці порожній список без помилки.","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fa-text-column-hides-it-1600x660.png",[38,560,562],{"id":561},"чи-id-у-вашому-фільтрі-тримає-чужі-рядки-ззовні","Чи id у вашому фільтрі тримає чужі рядки ззовні?",[10,564,565],{},"Ні. Фільтр вирішує, які рядки просить ваша сторінка. Які рядки відвідувачу можна\nчитати, вирішує Row Level Security, правила для кожного рядка, які Supabase\nперевіряє на кожному запиті з вашим публічним ключем, і будь-хто може надіслати\nваш запит знову з іншим id або зовсім без нього.",[10,567,568,569,572,573,577,578,580,581,584,585,588,589,592,593,597,598,602],{},"Один метод supabase-js показує різницю. ",[21,570,571],{},".match()"," приймає кілька колонок\nодразу, і\n",[62,574,576],{"href":351,"rel":575},[79],"його вихідний код","\nвикидає кожну колонку зі значенням ",[21,579,29],{},", перш ніж будувати запит. Саме для\nцього й був той коментар про ",[21,582,583],{},"eq.undefined",". Тож\n",[21,586,587],{},".match({ user_id: user?.id })",", зроблений до того, як завантажився користувач,\nне надсилає жодного фільтра, не дає жодної помилки і повертає всі рядки, які\nправила таблиці дозволяють цьому відвідувачу читати. Додайте до цього виклику\n",[21,590,591],{},".single()",", і він упаде інакше, з\n",[62,594,596],{"href":595},"\u002Fblog\u002Fsupabase-single-row-error","JSON object requested, multiple (or no) rows returned",",\nбо повернулося більше одного рядка. Коли правила ввімкнені, це все одно лише\nрядки самого відвідувача. Коли вимкнені, це вся таблиця, а\n",[62,599,601],{"href":600},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","як увімкнути їх для кожної таблиці","\nописує перемикач і перше правило.",[10,604,605,606,610],{},"Чи віддає таблиця рядки незнайомцеві, видно ззовні. Наше\n",[62,607,609],{"href":608},"\u002Fsecurity-scanner","безкоштовне сканування"," читає ваш живий застосунок тим самим\nпублічним ключем, який отримує відвідувач, повідомляє, які таблиці відповідають\nрядками, і не потребує облікового запису.",[38,612,614],{"id":613},"перш-ніж-змінювати-колонку-яку-читає-ваш-застосунок","Перш ніж змінювати колонку, яку читає ваш застосунок",[10,616,617],{},"Збережіть копію бази з часу до зміни типу колонки і дізнайтеся, коли якась\nтаблиця почне відповідати незнайомцям.",[10,619,620],{},[409,621,622,626],{},[62,623,625],{"href":624},"\u002Fsupabase-backups","Reeve Care"," зберігає копію вашої бази даних Supabase:",[403,628,629,632,635,638,641,644],{},[406,630,631],{},"зашифрована копія за розкладом, у власному сховищі Reeve в ЄС, поза вашим обліковим записом Supabase",[406,633,634],{},"кожна таблиця з рядками такими, якими вони були до того, як ви змінили тип колонки",[406,636,637],{},"кожна копія перевірена, перш ніж її зараховують, підрахунком рядків у кожній таблиці",[406,639,640],{},"ваші завантажені файли теж, щойно ви підключите облікові дані Storage",[406,642,643],{},"відновлення одним кліком, перед яким береться страхувальна копія поточного стану",[406,645,646],{},"усе, що робить Monitor",[10,648,649],{},[409,650,651,655],{},[62,652,654],{"href":653},"\u002Fwebsite-monitoring","Reeve Monitor"," і далі перевіряє ззовні:",[403,657,658,661,664,671],{},[406,659,660],{},"чи доступний ваш застосунок, з перевіркою щохвилини",[406,662,663],{},"повна перевірка безпеки щогодини, до трьох застосунків",[406,665,666,667,670],{},"повідомлення, коли результат ",[409,668,669],{},"змінюється",", тож таблиця, яка після деплою почала відповідати незнайомцям, дійде до вас, і вам не доведеться йти дивитися",[406,672,673],{},"щомісячний звіт простою мовою про те, що він побачив",[38,675,677],{"id":676},"що-зробити-зараз","Що зробити зараз",[679,680,681],"key-takeaways",{},[403,682,683,686,702,710,718,727],{},[406,684,685],{},"Прочитайте значення в лапках. Це саме те, що надіслав ваш застосунок.",[406,687,688,689,320,691,693,694,697,698,701],{},"Для ",[21,690,218],{},[21,692,231],{}," притримайте запит, доки не з'явиться id: ",[21,695,696],{},"if (!user?.id) return"," або ",[21,699,700],{},"enabled: !!user?.id"," у TanStack Query.",[406,703,688,704,706,707,337],{},[21,705,248],{}," шукайте порожні значення через ",[21,708,709],{},".is('column', null)",[406,711,688,712,714,715,717],{},[21,713,275],{}," передавайте ",[21,716,443],{}," об'єкта.",[406,719,720,721,723,724,726],{},"Залиште колонку типу ",[21,722,47],{}," і змінюйте її на ",[21,725,19],{}," лише тоді, коли id приходять від сервісу, що не видає uuid, як-от Clerk.",[406,728,729,730,732],{},"Якщо виклик ",[21,731,571],{}," з відсутнім значенням повертає чужі рядки, увімкніть Row Level Security для цієї таблиці.",[10,734,735,736,739],{},"Почніть із лапок, бо значення в них вказує на рядок вашого застосунку, який його\nнадіслав. Якщо виправлення, яке вам пропонують, змінює тип колонки,\n",[62,737,738],{"href":624},"збережіть копію бази"," з часу до зміни.",{"title":23,"searchDepth":741,"depth":741,"links":742},3,[743,745,746,747,748,749,750,751],{"id":40,"depth":744,"text":41},2,{"id":190,"depth":744,"text":191},{"id":330,"depth":744,"text":331},{"id":455,"depth":744,"text":456},{"id":520,"depth":744,"text":521},{"id":561,"depth":744,"text":562},{"id":613,"depth":744,"text":614},{"id":676,"depth":744,"text":677},"Основи безпеки","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcover-1200x630.png","Етикетка посилки з полем коду з п'яти клітинок, а перед нею бирка з бурштиновим undefined, задовга, щоб поміститися.","Supabase \"invalid input syntax for type uuid\" означає, що застосунок надіслав щось, що не є id. Прочитайте лапки, притримайте запит, залиште колонку.",false,"md",[759,762,765,768,771],{"q":760,"a":761},"Що означає invalid input syntax for type uuid?","Це означає, що Postgres мав прочитати значення як uuid, а значення записане не так, як uuid, тож він відхилив запит, нічого не прочитавши і не змінивши. Код 22P02, застосунок на Supabase отримує його як HTTP 400, а в лапках наприкінці повідомлення стоїть саме те, що надіслав ваш застосунок.",{"q":763,"a":764},"Чому мій id дорівнює undefined?","Бо запит пішов раніше, ніж з'явилося значення, або бо він читає назву, під якою нічого немає. Під час першого відмальовування сторінки користувача, що увійшов, ще могли не прочитати, тож user?.id дорівнює undefined, а маршрут, що називає значення projectId, щоразу дає undefined сторінці, яка читає id. supabase-js записує відсутнє значення в запит словом undefined.",{"q":766,"a":767},"Чи варто змінити колонку на text або перетворити значення?","Не для того, щоб виправити цю помилку. Колонка text приймає слово undefined, порівнює його з кожним id, не знаходить жодного, і ваша сторінка показує порожній список без жодної помилки. Змінюйте колонку, лише коли id, які ви зберігаєте, взагалі не uuid, як-от id користувачів Clerk, які власний посібник Clerk для Supabase тримає в колонці text.",{"q":769,"a":770},"Чому це стається лише під час першого завантаження?","Бо на наступному відмальовуванні id уже є, і той самий запит працює. Сторінка може заповнитися за мить і виглядати нормально, тоді як кожен візит усе одно надсилає один невдалий запит з undefined усередині. Притримайте запит, доки id не з'явиться, і цей запит не піде ніколи.",{"q":772,"a":773},"Як не дати запиту піти зарано?","Виходьте до виклику, поки id немає, наприклад рядком if (!user?.id) return на початку ефекту, і додайте user?.id до залежностей ефекту, щоб він запустився знову, щойно id з'явиться. У TanStack Query задайте enabled: !!user?.id. Тим часом показуйте стан завантаження.","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",[776,777,778,779,780,781,782,783],"invalid input syntax for type uuid","invalid input syntax for type uuid undefined","supabase помилка uuid","postgres 22p02","supabase недійсний uuid","supabase id undefined","invalid input syntax for type uuid null","supabase eq undefined",{},true,"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","2026-10-25",{"title":5,"description":755},"blog\u002Finvalid-input-syntax-for-type-uuid",[791,792,793],"Supabase \"invalid input syntax for type uuid\" (код Postgres 22P02, HTTP 400 у вашому застосунку) означає, що колонка uuid отримала значення, яке не є uuid. У лапках стоїть саме те, що надіслав ваш застосунок.","\"undefined\" у лапках означає, що запит пішов раніше, ніж з'явився id, бо supabase-js записує відсутнє значення в запит саме цим словом. Притримайте запит, доки id не з'явиться.","Залиште колонку типу uuid. Якщо змінити її на text, гучна помилка перетвориться на сторінку, яка мовчки нічого не показує.","3p2XhGtMMtG2CoXyenD4gaqBo-5bfT8XG_XztoDlM48",[796,802,808,814,820,826,832,838,844,850,856,863,869,875,881,887,888,894,900,905,911,917,923,929,935,941,946,952,958,964,970,976,982,988,994,1000,1006,1012,1018,1024,1030,1036,1042,1048,1054,1060,1065,1071,1077,1083,1089,1095,1101,1107,1113,1119,1125,1131,1137,1143,1149,1155,1160,1166,1172,1178,1184,1190,1196,1202,1208,1214,1220,1226,1232,1238,1244,1250,1256,1262,1268,1274,1280,1286,1291,1297,1303,1309,1314,1320],{"path":797,"title":798,"description":799,"published":800,"category":752,"image":801,"draft":756},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\": пояснення","Supabase \"max client connections reached\": у пулера немає місця ще для одного клієнта. Ліміт визначає порт у вашому рядку підключення.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":803,"title":804,"description":805,"published":806,"category":752,"image":807,"draft":756},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Помилка Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": вхід через Google вимкнено у вашому проєкті Supabase. Як увімкнути та виправити redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":809,"title":810,"description":811,"published":812,"category":752,"image":813,"draft":756},"\u002Fblog\u002Fviolates-foreign-key-constraint","Помилка Supabase \"violates foreign key constraint\" під час вставки","Supabase \"insert or update on table violates foreign key constraint\": ваш рядок посилається на рядок, якого немає. Який, чому і як це виправити.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":815,"title":816,"description":817,"published":818,"category":752,"image":819,"draft":756},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Помилка Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": обовʼязковий стовпець прийшов порожнім. Звідки взявся null і як це виправити.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":821,"title":822,"description":823,"published":824,"category":752,"image":825,"draft":756},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": куди поділася сесія","\"Auth session missing!\" означає, що supabase-js не знайшла жодної сесії й навіть не спитала Supabase. Куди поділася сесія і як це виправити.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":827,"title":828,"description":829,"published":830,"category":752,"image":831,"draft":756},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": ніхто не ввійшов","\"invalid claim: missing sub claim\": Supabase Auth отримав справжній токен без жодного користувача, ключ проєкту замість сесії.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":833,"title":834,"description":835,"published":836,"category":752,"image":837,"draft":756},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": справжня причина","\"Failed to send a request to the Edge Function\": браузер не отримав відповіді, яку можна прочитати. Його консоль каже, чому, і чи ваша функція запускалася.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":839,"title":840,"description":841,"published":842,"category":752,"image":843,"draft":756},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Чому Supabase перенаправляє посилання з листів на localhost:3000","Якщо Supabase перенаправляє на localhost:3000, Site URL так і не змінили або вашої адреси немає в Redirect URLs. Як виправити і якої маски уникати.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":845,"title":846,"description":847,"published":848,"category":752,"image":849,"draft":756},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" на новому посиланні","На посиланні, надісланому хвилину тому, \"Email link is invalid or has expired\" у Supabase зазвичай означає, що поштовий фільтр використав його першим.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":851,"title":852,"description":853,"published":854,"category":752,"image":855,"draft":756},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\": пояснення","Supabase \"canceling statement due to statement timeout\": запит перевищив ліміт своєї ролі, 3 секунди для відвідувача. Спершу перевірте політику RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":857,"title":858,"description":859,"published":860,"category":861,"image":862,"draft":756},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" у Supabase і що зникає разом","\"Database error deleting user\" у Supabase: ваша база відмовилася видаляти. Причина в логах, а виправлення вирішує, що ще буде видалено.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":864,"title":865,"description":866,"published":867,"category":752,"image":868,"draft":756},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" у Supabase","Вебхук Stripe в Edge Function Supabase пише \"No signatures found matching the expected signature\"? Причин дві. Не вимикайте перевірку.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":870,"title":871,"description":872,"published":873,"category":752,"image":874,"draft":756},"\u002Fblog\u002Fsupabase-invalid-login","\"Invalid login credentials\" у Supabase: три причини","Supabase відповідає \"Invalid login credentials\" на неправильний пароль, невідому пошту й акаунт Google. Як зрозуміти, що саме.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":876,"title":877,"description":878,"published":879,"category":752,"image":880,"draft":756},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": справжня помилка","\"Edge Function returned a non-2xx status code\" означає, що ваша функція Supabase відповіла помилкою. Ось де прочитати справжню.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":882,"title":883,"description":884,"published":885,"category":752,"image":886,"draft":756},"\u002Fblog\u002Fcertificate-not-trusted","Сертифікат не довірений: три причини, крім закінчення строку","Сертифікат не довірений, хоча дата в порядку? Він називає іншу адресу, підписав сам себе або в його ланцюжку бракує ланки. Як зрозуміти, що саме.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":786,"title":5,"description":755,"published":787,"category":752,"image":774,"draft":756},{"path":889,"title":890,"description":891,"published":892,"category":752,"image":893,"draft":756},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\": пояснення","Supabase \"duplicate key value violates unique constraint\": значення вже зайняте. Знайдіть стовпець, оберіть виправлення й сховайте значення від очей.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":895,"title":896,"description":897,"published":898,"category":752,"image":899,"draft":756},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\", хоча таблиця на місці","Supabase \"relation does not exist\" або PGRST205: жодна таблиця не має такої назви в цій схемі. Чотири перевірки, і на що зважити, відкриваючи схему.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":391,"title":901,"description":902,"published":903,"category":752,"image":904,"draft":756},"Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" показує назви аргументів, які надіслав ваш застосунок. Порівняйте їх із функцією.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":906,"title":907,"description":908,"published":909,"category":752,"image":910,"draft":756},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" зазвичай означає, що назва не збігається. Чотири перевірки і рядок для перезавантаження.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":912,"title":913,"description":914,"published":915,"category":752,"image":916,"draft":756},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": два ліміти, один код помилки","Supabase \"Email Rate Limit Exceeded\" обмежує кожен лист вашого проєкту: 2 на годину з вбудованим відправником. Що враховується і як підняти ліміт.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":918,"title":919,"description":920,"published":921,"category":752,"image":922,"draft":756},"\u002Fblog\u002Fsupabase-users-logged-out","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 причини","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" виводить ваших користувачів із системи. Три причини і як лог Auth їх розрізняє.","2026-10-19","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",{"path":924,"title":925,"description":926,"published":927,"category":752,"image":928,"draft":756},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": три причини","Supabase \"permission denied for schema public\" означає, що бракує GRANT на схему. Що його прибрало і який рядок його повертає.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":930,"title":931,"description":932,"published":933,"category":752,"image":934,"draft":756},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": три речі, які це може означати","Supabase \"Bucket not found\" означає одне з трьох: публічне посилання на приватний бакет, неточну назву або не той проєкт.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":936,"title":937,"description":938,"published":939,"category":752,"image":940,"draft":756},"\u002Fblog\u002Fsupabase-invalid-jwt","Supabase invalid JWT: який ключ перестав працювати?","Помилка Supabase invalid JWT — це PGRST301: підписаний токен не пройшов перевірку. У новому проєкті йдеться про сесію, а не про ключ API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":595,"title":942,"description":943,"published":944,"category":752,"image":945,"draft":756},"Supabase \"multiple (or no) rows returned\" майже завжди означає нуль","Supabase повертає PGRST116, \"JSON object requested, multiple (or no) rows returned\", коли запит нічого не знайшов. Прихований рядок має вигляд відсутнього.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":947,"title":948,"description":949,"published":950,"category":752,"image":951,"draft":756},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" у Supabase: де шукати","\"Database error saving new user\" означає, що щось причеплене до вашої реєстрації в Supabase впало. Справжня помилка лежить у ваших логах.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":953,"title":954,"description":955,"published":956,"category":752,"image":957,"draft":756},"\u002Fblog\u002Fwhat-is-supabase","Що таке Supabase? База даних, яку обрав ваш білдер","Що таке Supabase: база даних, вхід і сховище файлів за вашим застосунком. Supabase тримає сервери, а правила про те, хто читає ваші рядки, ваші.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":959,"title":960,"description":961,"published":962,"category":752,"image":963,"draft":756},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Відкритий у фронтенді ключ AWS це не те саме, що ключ OpenAI","Ключ доступу AWS, відкритий у вашому фронтенді, читає і пише ваше сховище. Рішення зазвичай presigned URL, а не новий ключ.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":965,"title":966,"description":967,"published":968,"category":752,"image":969,"draft":756},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" при вивантаженні","\"New row violates row-level security policy for table objects\" означає, що вашому вивантаженню бракує правила insert. Публічний бакет його не додає.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":971,"title":972,"description":973,"published":974,"category":752,"image":975,"draft":756},"\u002Fblog\u002Fbase44-security-scan","Сканування безпеки Base44: те, що бачить лише воно","Сканування безпеки Base44 перевіряє сім видів проблем зсередини. Ось половина, яку читає тільки воно, і половина, на яку воно ніколи не дивиться.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":977,"title":978,"description":979,"published":980,"category":752,"image":981,"draft":756},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Ваш API-ключ витік. Порядок дій","API-ключ витік, і ви не знаєте, що робити першим. Не кожен ключ у вашому фронтенді є витоком, а порядок важить більше за швидкість.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":983,"title":984,"description":985,"published":986,"category":752,"image":987,"draft":756},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" без вимкнення RLS","\"Infinite recursion detected in policy for relation\" означає, що ваша policy запитала таблицю, яку вона захищає. Ось як розірвати коло.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":989,"title":990,"description":991,"published":992,"category":752,"image":993,"draft":756},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" у Supabase, і хибне виправлення","\"No API key found in request\" означає, що запит дійшов до Supabase без ключа. Більшість відповідей натомість вказують на правила вашої бази.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":995,"title":996,"description":997,"published":998,"category":752,"image":999,"draft":756},"\u002Fblog\u002Fis-base44-safe","Чи безпечний Base44? Дані 5 442 застосунків","Чи безпечний Base44? Ми прогнали дев’ять перевірок на 5 442 робочих застосунках Base44. Майже всі отримали B з причин, яких власник ніколи не обирав.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":1001,"title":1002,"description":1003,"published":1004,"category":752,"image":1005,"draft":756},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Сховати ключ API: перенесіть його в Supabase Edge Function","Сховати ключ API означає прибрати його з браузера, а Supabase Edge Function це найменше місце, куди його покласти. Два кроки поруч важать більше.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":1007,"title":1008,"description":1009,"published":1010,"category":752,"image":1011,"draft":756},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Чи відкритий ваш файл .env? Дванадцять шляхів для перевірки","Чи відкритий ваш файл .env на вашому власному вебсервері? Дванадцять адрес скажуть це за хвилину, а влучання означає, що все в ньому вже публічне.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":1013,"title":1014,"description":1015,"published":1016,"category":752,"image":1017,"draft":756},"\u002Fblog\u002Fis-v0-safe","Безпека v0: усі 1 790 просканованих застосунків v0 отримали A","Безпека v0 на 1 790 живих застосунках v0: усі отримали A. Лише 17 згадували базу даних, і саме це здебільшого вимірює оцінка A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":1019,"title":1020,"description":1021,"published":1022,"category":752,"image":1023,"draft":756},"\u002Fblog\u002Fis-bolt-safe","Чи безпечний Bolt? Що показали 1 123 застосунки Bolt","Чи безпечний Bolt? Ми прогнали 1 123 живі застосунки Bolt через дев’ять перевірок. Хостинг був чистим. Знахідки: ключі й відкриті таблиці в самих застосунках.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":1025,"title":1026,"description":1027,"published":1028,"category":752,"image":1029,"draft":756},"\u002Fblog\u002Fis-supabase-down-or-your-app","Supabase не працює чи проблема у вашому застосунку? Як розрізнити","Supabase не працює чи зламався ваш застосунок? Пауза, повна база й ваша власна помилка виглядають однаково. Чотири перевірки їх розрізняють.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":1031,"title":1032,"description":1033,"published":1034,"category":752,"image":1035,"draft":756},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","Чи шифрує Supabase мої дані? Так. Ось від чого це захищає","Чи шифрує Supabase дані? Так: AES-256 у стані спокою, TLS під час передавання, SOC 2 та ISO 27001. Що покриває кожне і який витік не зупиняє жодне.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":1037,"title":1038,"description":1039,"published":1040,"category":752,"image":1041,"draft":756},"\u002Fblog\u002Fsupabase-free-plan-limits","Ліміти безкоштовного тарифу Supabase і що стається на кожному","Ліміти безкоштовного тарифу Supabase: 500 МБ бази, 5 ГБ egress і жодних резервних копій. Що стається на кожній межі і що змінює Pro за $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":1043,"title":1044,"description":1045,"published":1046,"category":861,"image":1047,"draft":756},"\u002Fblog\u002Ftest-your-supabase-backup","Перевірте резервну копію Supabase до того, як вона знадобиться","Як перевірити резервну копію Supabase: відновити в тестовий проєкт, порахувати рядки, увійти й знайти рядок, якого бракує обрізаному файлу.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":1049,"title":1050,"description":1051,"published":1052,"category":861,"image":1053,"draft":756},"\u002Fblog\u002Fsupabase-backup-github-action","Безкоштовна резервна копія Supabase через GitHub Action і підступ","Резервна копія Supabase через GitHub Action безкоштовна й годиться багатьом застосункам. Робочий процес, потрібний рядок підключення та egress.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":1055,"title":1056,"description":1057,"published":1058,"category":861,"image":1059,"draft":756},"\u002Fblog\u002Fdownload-your-supabase-backup","Чому ви не можете завантажити резервну копію Supabase","Завантажити резервну копію Supabase на сучасному проєкті не вийде: щоденна копія там фізична. Як це перевірити і як тримати власну копію.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":1061,"title":1062,"description":1063,"published":1058,"category":752,"image":1064,"draft":756},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": бракує GRANT","З 30 жовтня нова таблиця в Supabase відповідає \"permission denied for table\", доки ви не дасте доступ. Лист показує лише половину виправлення.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":1066,"title":1067,"description":1068,"published":1069,"category":752,"image":1070,"draft":756},"\u002Fblog\u002Fopen-api-endpoint-exposed","Чи є відкритий API-ендпоінт проблемою безпеки? Читайте JSON","Ваше сканування позначило відкритий API-ендпоінт. Чи це важливо, залежить від того, що повернулося, і більшість знайдених належали платформі.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":1072,"title":1073,"description":1074,"published":1075,"category":752,"image":1076,"draft":756},"\u002Fblog\u002Flovable-security-scan","Сканування безпеки Lovable: чого воно не доведе","Сканування безпеки Lovable: що перевіряють Quick scan і Deep scan, коли запускається кожне, і єдине, чого не доведе жодне сканування зсередини.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":1078,"title":1079,"description":1080,"published":1081,"category":861,"image":1082,"draft":756},"\u002Fblog\u002Fsupabase-backup-auth-users","Чому у вашому дампі Supabase немає користувачів","Запустіть supabase db dump окремо і отримаєте форму вашої бази та жодного її рядка, без схеми auth, у якій живуть ваші користувачі.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":1084,"title":1085,"description":1086,"published":1087,"category":752,"image":1088,"draft":756},"\u002Fblog\u002Fdomain-and-certificate-expiry","Домен закінчився, сайт лежить: що буде далі","Ваш домен закінчився і сайт лежить. Ось який годинник уже пішов, чому прострочений сертифікат це менша з двох бід, і як перевірити обидва.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":1090,"title":1091,"description":1092,"published":1093,"category":752,"image":1094,"draft":756},"\u002Fblog\u002Fis-lovable-safe","Чи безпечний Lovable? Що показали 18 554 застосунки Lovable","Чи безпечний Lovable? Ми прогнали 18 554 живі застосунки Lovable через дев’ять перевірок. Платформа виявилася найчистішою з п’яти. Знахідки були в застосунках.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":1096,"title":1097,"description":1098,"published":1099,"category":752,"image":1100,"draft":756},"\u002Fblog\u002Fvibe-coded-app-security-checklist","Чек-лист безпеки для vibe coding, у девʼяти перевірках","Чек-лист безпеки для vibe coding із девʼяти пунктів, кожен з яких будь-хто може перевірити у вашому живому застосунку ззовні, і кожен має тест на один рядок.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":1102,"title":1103,"description":1104,"published":1105,"category":752,"image":1106,"draft":756},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Секретний ключ Stripe у фронтенді може рухати гроші","Секретний ключ Stripe, відкритий у вашому фронтенді, може повертати кошти, списувати й читати кожну картку клієнта. А ключ pk_live_ там і має бути.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":1108,"title":1109,"description":1110,"published":1111,"category":752,"image":1112,"draft":756},"\u002Fblog\u002Fvite-and-next-public-env-vars","Змінні оточення Vite відкриті: префікс означає опублікувати це","Змінні оточення Vite відкриті у вашому застосунку, бо так просив префікс. VITE_ і NEXT_PUBLIC_ означають опублікувати це, а ШІ, який їх додав, не знав ціни.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":1114,"title":1115,"description":1116,"published":1117,"category":752,"image":1118,"draft":756},"\u002Fblog\u002Fbase44-source-maps","Безпека Base44: що позначає скан і що з цього виправляти вам","Безпека Base44 на 5 438 просканованих застосунках: три знахідки майже на кожному належать платформі, source map є бейджем Base44, а ваша частина коротка.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":1120,"title":1121,"description":1122,"published":1123,"category":752,"image":1124,"draft":756},"\u002Fblog\u002Fis-cursor-ai-safe","Чи безпечний Cursor AI? Редактор, код і опублікований застосунок","Чи безпечний Cursor AI? Три запитання в одному пошуку: що Cursor зберігає, у чому помиляється його код і чи відкритий застосунок, який ви опублікували.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":1126,"title":1127,"description":1128,"published":1129,"category":752,"image":1130,"draft":756},"\u002Fblog\u002Fis-replit-safe","Чи безпечний Replit? Що ми знайшли в 3 042 живих застосунках Replit","Чи безпечний Replit? Ми прогнали 3 042 живі застосунки Replit через дев’ять зовнішніх перевірок. Знахідки були в опублікованому застосунку, а не в хостингу.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":1132,"title":1133,"description":1134,"published":1135,"category":861,"image":1136,"draft":756},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: у копії бази даних немає жодного файлу","Supabase storage backup це окрема робота. Копії бази даних зберігають список ваших файлів і жодного з них, тож після відновлення кожне завантаження зламане.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":1138,"title":1139,"description":1140,"published":1141,"category":861,"image":1142,"draft":756},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery у Supabase: ціна та межі","Point-in-time recovery у Supabase відмотує базу на будь-яку секунду за останній тиждень. Коштує $100 на місяць понад Pro і покриває лише базу даних.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":1144,"title":1145,"description":1146,"published":1147,"category":861,"image":1148,"draft":756},"\u002Fblog\u002Fsupabase-project-paused-recover","Проєкт Supabase на паузі? Ваші дані нікуди не зникли","Supabase поставив ваш проєкт на паузу після тижня без активності. Нічого не видалено, кнопка Restore стоїть поруч із назвою, і у вас є рік, щоб натиснути.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":1150,"title":1151,"description":1152,"published":1153,"category":752,"image":1154,"draft":756},"\u002Fblog\u002Fsafest-ai-app-builder","Який білдер застосунків з ШІ найбезпечніший? 30 998 тестів","Який білдер застосунків з ШІ найбезпечніший? Ми просканували 30 998 живих застосунків з Lovable, Base44, Replit, v0 і Bolt. Оцінку вирішує не білдер.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":600,"title":1156,"description":1157,"published":1158,"category":752,"image":1159,"draft":756},"Увімкніть Row Level Security на кожній таблиці Supabase і перевірте","Row Level Security у Supabase без політики закриває таблицю повністю. Політика без увімкненого перемикача не робить нічого. Ось SQL, і ось перевірка.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":1161,"title":1162,"description":1163,"published":1164,"category":752,"image":1165,"draft":756},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": чого не бачить попередження","Supabase позначає \"RLS disabled in public\" як помилку. Про політику читання, яка лишає вашу таблицю так само відкритою, він не каже нічого.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":1167,"title":1168,"description":1169,"published":1170,"category":752,"image":1171,"draft":756},"\u002Fblog\u002Frotate-supabase-service-role-key","Як замінити злитий ключ service_role у Supabase","Supabase каже спершу закрити витік. Інші посібники кажуть міняти негайно. Що правильно, залежить від того, куди саме потрапив ваш ключ service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1173,"title":1174,"description":1175,"published":1176,"category":752,"image":1177,"draft":756},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Сканери безпеки для vibe coding у порівнянні, наш теж","Найкращий сканер безпеки для vibe coding залежить від трьох питань, на які не відповідає жоден перелік функцій. Вісім інструментів і ціни.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1179,"title":1180,"description":1181,"published":1182,"category":752,"image":1183,"draft":756},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: п’ять перевірок, які зробите самі","Supabase security checker читає ваш опублікований застосунок, а не налаштування проєкту. Ось п’ять перевірок і як виконати кожну самостійно.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1185,"title":1186,"description":1187,"published":1188,"category":752,"image":1189,"draft":756},"\u002Fblog\u002Fvibe-coding-security-scanner","Сканер безпеки для vibe coding: чого не бачить скан URL","Сканер безпеки для vibe coding читає ваш робочий застосунок ззовні. Що це охоплює, чотири речі, яких він не бачить, і як читати результат.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1191,"title":1192,"description":1193,"published":1194,"category":752,"image":1195,"draft":756},"\u002Fblog\u002Fmissing-security-headers","Відсутні заголовки безпеки: коли це справді важливо","Відсутні заголовки безпеки трапляються в наших звітах найчастіше. Від чого вони захищають і коли це найменш терміновий рядок вашого звіту.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1197,"title":1198,"description":1199,"published":1200,"category":752,"image":1201,"draft":756},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Ваш ключ API OpenAI відкритий у фронтенді. Замініть його.","Ключ API OpenAI, відкритий у фронтенді, не можна прив'язати до домену. Замініть його сьогодні, перенесіть виклик на свій сервер і обмежте витрати.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1203,"title":1204,"description":1205,"published":1206,"category":752,"image":1207,"draft":756},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Ключ API у фронтенді: що насправді віддають 30 998 застосунків","Ключ API, відкритий у вашому фронтенді, зазвичай є ключем Google Maps. Ми просканували 30 998 vibe-coded застосунків і порахували, що витікає насправді.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1209,"title":1210,"description":1211,"published":1212,"category":861,"image":1213,"draft":756},"\u002Fblog\u002Fsupabase-backup-tools-compared","Інструменти резервного копіювання Supabase, і наш серед них","Чотири види інструментів резервного копіювання Supabase, що копіює кожен і коли безкоштовна GitHub Action виграє в будь-якої оплати, нашої теж.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1215,"title":1216,"description":1217,"published":1218,"category":752,"image":1219,"draft":756},"\u002Fblog\u002Freplit-secrets-explained","Як користуватися секретами в Replit і що все одно публікується","Як користуватися секретами в Replit: додати, прочитати і усунути дві причини undefined. А ще ключі, які цей інструмент не здатен зберегти в таємниці.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1221,"title":1222,"description":1223,"published":1224,"category":861,"image":1225,"draft":756},"\u002Fblog\u002Fback-up-supabase-free-tier","Резервні копії на безкоштовному тарифі Supabase без терміналу","На безкоштовному тарифі Supabase резервних копій немає: копію робите ви. Як зробити її з панелі та що втрачає шлях через CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1227,"title":1228,"description":1229,"published":1230,"category":752,"image":1231,"draft":756},"\u002Fblog\u002Fis-supabase-secure","Чи безпечний Supabase? Так. Ваш проєкт це інше питання","Чи безпечний Supabase? Платформа проходить аудити, шифрує дані й тримає пентести. Їхня документація каже, де це закінчується і починаються ваші налаштування.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1233,"title":1234,"description":1235,"published":1236,"category":752,"image":1237,"draft":756},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Де знайти API-ключі Supabase: anon, service_role і URL","URL проєкту, ключ anon і ключ service_role лежать на одній сторінці панелі. Ось де вона, і яке з чотирьох значень має бути у вашому застосунку.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1239,"title":1240,"description":1241,"published":1242,"category":752,"image":1243,"draft":756},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy в Supabase. Що далі?","\"New row violates row-level security policy\" означає, що Supabase відмовив у записі. Швидке виправлення знову відкриває таблицю для всіх.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1245,"title":1246,"description":1247,"published":1248,"category":752,"image":1249,"draft":756},"\u002Fblog\u002Fcors-wildcard-security-risk","Чи є вайлдкард CORS ризиком для безпеки? Майже ніколи.","Чи є вайлдкард CORS ризиком для безпеки? Зазвичай це типове налаштування вашого білдера, і воно не видає нічого, що ваш сервер і так віддавав кожному.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1251,"title":1252,"description":1253,"published":1254,"category":861,"image":1255,"draft":756},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Branching у Supabase це не бекап. Він іде тільки вперед.","Чому branching у Supabase це не бекап: гілка стартує без ваших даних, а мердж переносить саму лише схему. Для чого він потрібен і що брати замість нього.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1257,"title":1258,"description":1259,"published":1260,"category":861,"image":1261,"draft":756},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Як відновити резервну копію Supabase, і що ламається потім","Як відновити резервну копію Supabase з панелі або з файлу дампа, що саме замінює відновлення і чому ваш застосунок може лишитися зламаним після нього.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1263,"title":1264,"description":1265,"published":1266,"category":752,"image":1267,"draft":756},"\u002Fblog\u002Fsupabase-storage-bucket-public","Ваш бакет Supabase Storage публічний. Чи це проблема?","Публічний бакет Supabase Storage означає, що той, хто має URL файлу, може його відкрити. Він не означає, що хтось може переглянути список вмісту.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1269,"title":1270,"description":1271,"published":1272,"category":752,"image":1273,"draft":756},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Чи є проблемою ключ API Google у вашому браузері?","Ключ API Google у відкритому коді сторінки наш сканер знаходить найчастіше, і зазвичай усе гаразд. Вирішує це одне безкоштовне налаштування.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1275,"title":1276,"description":1277,"published":1278,"category":861,"image":1279,"draft":756},"\u002Fblog\u002Fai-agent-deleted-my-database","ШІ-агент видалив мої дані в Supabase. Що можна відновити?","ШІ-агент видалив дані з вашої бази. Те, що ви зможете відновити, вирішилося раніше, а наступні хвилини вирішують, скільки з цього вціліє.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1281,"title":1282,"description":1283,"published":1284,"category":752,"image":1285,"draft":756},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Чи може будь-хто прочитати вашу базу Supabase? 3 680 застосунків","Чи може будь-хто прочитати вашу базу даних Supabase без входу? Ми просканували 30 998 живих застосунків, зроблених ШІ-білдерами, і виміряли, як часто так.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1287,"title":1288,"description":1289,"published":1284,"category":752,"image":1290,"draft":756},"\u002Fblog\u002Fsource-maps-exposed-in-production","Відкриті source maps: ваш застосунок публікує свій вихідний код","Відкрита source map дає будь-кому прочитати оригінальний код вашого застосунку, разом із коментарями. Перевірка за 30 секунд, і що важить насправді.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1292,"title":1293,"description":1294,"published":1295,"category":752,"image":1296,"draft":756},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: це той самий anon key?","Supabase замінив anon і service_role публічними та секретними ключами. Який із них має бути у вашому застосунку, а який не має бути ніколи?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1298,"title":1299,"description":1300,"published":1301,"category":861,"image":1302,"draft":756},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Чи робить Supabase резервні копії моєї бази? Залежить від тарифу.","Чи робить Supabase резервні копії вашої бази даних? На платних тарифах щодня, на безкоштовному жодної. Як дізнатися, що у вас насправді є.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1304,"title":1305,"description":1306,"published":1307,"category":752,"image":1308,"draft":756},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security увімкнено. Таблиця досі публічна.","Увімкнути Supabase Row Level Security не означає захистити таблицю. Захищають політики, а та, що полагодила застосунок, часто впускає всіх.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1310,"title":1311,"description":1312,"published":1307,"category":861,"image":1313,"draft":756},"\u002Fblog\u002Fversion-history-is-not-a-backup","Історія версій не є резервною копією. Вона не поверне таблицю.","Lovable і Bolt ведуть історію версій вашого коду. Ваша база даних працює як окремий сервіс, тож відкат назад не поверне ваші дані.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1315,"title":1316,"description":1317,"published":1318,"category":861,"image":1319,"draft":756},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Три способи зробити резервну копію бази Supabase, і чого бракує","Панель, pg_dump і керований сервіс. Що насправді зберігає кожен спосіб, що тихо лишає осторонь і який із них переживе втрату акаунта.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":1321,"title":1322,"description":1323,"published":1318,"category":752,"image":1324,"draft":756},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","Які API-ключі безпечні у браузері, а які ні","Ваш ключ anon у Supabase створений, щоб бути публічним. Ключ service_role для цього не створений, і він ігнорує всі правила, які ви задали. Як їх розрізнити.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213654336]