<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Aswindanu Anwar</title>
    <description>The latest articles on DEV Community by Aswindanu Anwar (@aswindanu_anwar_38c31d278).</description>
    <link>https://dev.to/aswindanu_anwar_38c31d278</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4001897%2F66971193-cc7e-4cef-88d0-bcb6f7911043.png</url>
      <title>DEV Community: Aswindanu Anwar</title>
      <link>https://dev.to/aswindanu_anwar_38c31d278</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/aswindanu_anwar_38c31d278"/>
    <language>en</language>
    <item>
      <title>Proxying RabbitMQ Management UI Through Nginx (Fixing the %2F Problem)</title>
      <dc:creator>Aswindanu Anwar</dc:creator>
      <pubDate>Wed, 01 Jul 2026 09:40:01 +0000</pubDate>
      <link>https://dev.to/aswindanu_anwar_38c31d278/proxying-rabbitmq-management-ui-through-nginx-fixing-the-2f-problem-3dj0</link>
      <guid>https://dev.to/aswindanu_anwar_38c31d278/proxying-rabbitmq-management-ui-through-nginx-fixing-the-2f-problem-3dj0</guid>
      <description>&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;When you put RabbitMQ's Management UI behind an nginx reverse proxy under a&lt;br&gt;
sub-path like &lt;code&gt;/rabbitmq/&lt;/code&gt;, queue detail pages and many API calls break silently.&lt;/p&gt;

&lt;p&gt;The root cause: nginx normalizes the request URI before proxying. It decodes&lt;br&gt;
&lt;code&gt;%2F&lt;/code&gt; (the URL-encoded forward slash) into a literal &lt;code&gt;/&lt;/code&gt;. RabbitMQ's Management&lt;br&gt;
API uses &lt;code&gt;%2F&lt;/code&gt; to represent the &lt;strong&gt;default virtual host&lt;/strong&gt; (&lt;code&gt;/&lt;/code&gt;) in API paths:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/queues/%2F/my-queue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When nginx decodes it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GET /api/queues///my-queue   ← broken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  What Doesn't Work
&lt;/h2&gt;

&lt;p&gt;The common advice of using &lt;code&gt;merge_slashes off&lt;/code&gt; or a &lt;code&gt;rewrite&lt;/code&gt; directive doesn't&lt;br&gt;
fully solve this because nginx still normalizes &lt;code&gt;$uri&lt;/code&gt; before forwarding.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;$request_uri&lt;/code&gt; inside an &lt;code&gt;if&lt;/code&gt; block. Unlike &lt;code&gt;$uri&lt;/code&gt;, &lt;code&gt;$request_uri&lt;/code&gt; holds&lt;br&gt;
the &lt;strong&gt;raw, undecoded URI exactly as the client sent it&lt;/strong&gt; — nginx never touches it.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
nginx
# RabbitMQ: API paths — use $request_uri to preserve %2F (never decoded by nginx)
location ~* ^/rabbitmq/api/ {
    if ($request_uri ~* "^/rabbitmq/(.*)") {
        proxy_pass http://rabbitmq:15672/$1;
    }
    proxy_buffering off;
    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
}

# RabbitMQ: general UI (JS, CSS, static assets, non-API pages)
location ~* ^/rabbitmq/ {
    rewrite ^/rabbitmq/(.*)$ /$1 break;
    proxy_pass http://rabbitmq:15672;
    proxy_buffering off;
    proxy_set_header Host              $host;
    proxy_set_header X-Real-IP         $remote_addr;
    proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto https;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>nginx</category>
      <category>devops</category>
      <category>tutorial</category>
      <category>rabbitmq</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Aswindanu Anwar</dc:creator>
      <pubDate>Thu, 25 Jun 2026 09:04:08 +0000</pubDate>
      <link>https://dev.to/aswindanu_anwar_38c31d278/-2hga</link>
      <guid>https://dev.to/aswindanu_anwar_38c31d278/-2hga</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/aswindanu_anwar_38c31d278/the-only-guide-you-need-for-prisma-migration-conflicts-without-losing-data-6bc" class="crayons-story__hidden-navigation-link"&gt;The Only Guide You Need for Prisma Migration Conflicts (Without Losing Data)&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/aswindanu_anwar_38c31d278" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4001897%2F66971193-cc7e-4cef-88d0-bcb6f7911043.png" alt="aswindanu_anwar_38c31d278 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/aswindanu_anwar_38c31d278" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Aswindanu Anwar
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Aswindanu Anwar
                
              
              &lt;div id="story-author-preview-content-3986580" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/aswindanu_anwar_38c31d278" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4001897%2F66971193-cc7e-4cef-88d0-bcb6f7911043.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Aswindanu Anwar&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/aswindanu_anwar_38c31d278/the-only-guide-you-need-for-prisma-migration-conflicts-without-losing-data-6bc" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jun 25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/aswindanu_anwar_38c31d278/the-only-guide-you-need-for-prisma-migration-conflicts-without-losing-data-6bc" id="article-link-3986580"&gt;
          The Only Guide You Need for Prisma Migration Conflicts (Without Losing Data)
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/prisma"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;prisma&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/postgres"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;postgres&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/database"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;database&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/aswindanu_anwar_38c31d278/the-only-guide-you-need-for-prisma-migration-conflicts-without-losing-data-6bc" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;1&lt;span class="hidden s:inline"&gt;&amp;nbsp;reaction&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/aswindanu_anwar_38c31d278/the-only-guide-you-need-for-prisma-migration-conflicts-without-losing-data-6bc#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            5 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>The Only Guide You Need for Prisma Migration Conflicts (Without Losing Data)</title>
      <dc:creator>Aswindanu Anwar</dc:creator>
      <pubDate>Thu, 25 Jun 2026 08:01:45 +0000</pubDate>
      <link>https://dev.to/aswindanu_anwar_38c31d278/the-only-guide-you-need-for-prisma-migration-conflicts-without-losing-data-6bc</link>
      <guid>https://dev.to/aswindanu_anwar_38c31d278/the-only-guide-you-need-for-prisma-migration-conflicts-without-losing-data-6bc</guid>
      <description>&lt;h2&gt;
  
  
  The Only Guide You Need for Prisma Migration Conflicts (Without Losing Data)
&lt;/h2&gt;

&lt;p&gt;If you've ever seen this message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The migration `20240101_something` was modified after it was applied.
We need to reset the "public" schema.
All data will be lost.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Stop. Do not run &lt;code&gt;prisma migrate reset&lt;/code&gt;.&lt;/strong&gt; This guide will walk you through resolving every Prisma migration conflict without touching your data.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Golden Rule
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Never use &lt;code&gt;prisma migrate reset&lt;/code&gt; on a real database.&lt;/strong&gt;&lt;br&gt;
Every conflict has a manual resolution. Here's the playbook.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The pattern is always the same:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fix or create the SQL file&lt;/li&gt;
&lt;li&gt;Apply it manually with &lt;code&gt;prisma db execute&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tell Prisma it's done with &lt;code&gt;prisma migrate resolve --applied&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Before You Write Any SQL — Query the Actual DB First
&lt;/h2&gt;

&lt;p&gt;Do not guess. Before writing migration SQL, check what actually exists in your database. This prevents the back-and-forth ping-pong of "column doesn't exist" errors.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;container&amp;gt; sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'node -e "
const { Client } = require(\"pg\");
const client = new Client({ connectionString: process.env.DATABASE_URL });
client.connect()
  .then(() =&amp;gt; client.query(\"SELECT indexname, tablename FROM pg_indexes WHERE tablename = \$1\", [\"your_table\"]))
  .then(r =&amp;gt; { console.log(JSON.stringify(r.rows, null, 2)); client.end(); })
  .catch(e =&amp;gt; { console.error(e.message); client.end(); });
"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check columns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;container&amp;gt; sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'node -e "
const { Client } = require(\"pg\");
const client = new Client({ connectionString: process.env.DATABASE_URL });
client.connect()
  .then(() =&amp;gt; client.query(\"SELECT column_name, is_nullable, data_type, column_default FROM information_schema.columns WHERE table_name = \$1\", [\"your_table\"]))
  .then(r =&amp;gt; { console.log(JSON.stringify(r.rows, null, 2)); client.end(); })
  .catch(e =&amp;gt; { console.error(e.message); client.end(); });
"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check constraints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;container&amp;gt; sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'node -e "
const { Client } = require(\"pg\");
const client = new Client({ connectionString: process.env.DATABASE_URL });
client.connect()
  .then(() =&amp;gt; client.query(\"SELECT conname, contype, conrelid::regclass AS table_name FROM pg_constraint WHERE conrelid::regclass::text = \$1\", [\"your_table\"]))
  .then(r =&amp;gt; { console.log(JSON.stringify(r.rows, null, 2)); client.end(); })
  .catch(e =&amp;gt; { console.error(e.message); client.end(); });
"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Case 1 — Migration Failed Mid-Run (P3018)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Error:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A migration failed to apply. New migrations cannot be applied before the error is recovered from.
Migration name: 20240101_something
Database error: ERROR: column "xyz" does not exist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read the error. Fix the SQL file.&lt;/li&gt;
&lt;li&gt;Roll it back (only works if migration is in failed state):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma migrate resolve &lt;span class="nt"&gt;--rolled-back&lt;/span&gt; 20240101_something
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Apply the fixed SQL manually:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma db execute &lt;span class="nt"&gt;--file&lt;/span&gt; prisma/migrations/20240101_something/migration.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Mark it as applied:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma migrate resolve &lt;span class="nt"&gt;--applied&lt;/span&gt; 20240101_something
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Case 2 — Checksum Mismatch (Migration Modified After Being Applied)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Error:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The migration `20240101_something` was modified after it was applied.
We need to reset the "public" schema.
All data will be lost.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Compute the SHA-256 of your current migration file:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# PowerShell&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Get-FileHash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prisma/migrations/20240101_something/migration.sql"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Algorithm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SHA256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Hash&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;Write-Output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$hash&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# bash/Linux&lt;/span&gt;
&lt;span class="nb"&gt;sha256sum &lt;/span&gt;prisma/migrations/20240101_something/migration.sql
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Update &lt;strong&gt;ALL rows&lt;/strong&gt; for that migration in &lt;code&gt;_prisma_migrations&lt;/code&gt; — Prisma keeps rolled-back history rows and checks those too. Filtering by &lt;code&gt;rolled_back_at IS NULL&lt;/code&gt; is NOT enough:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;container&amp;gt; sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'node -e "
const { Client } = require(\"pg\");
const client = new Client({ connectionString: process.env.DATABASE_URL });
client.connect().then(async () =&amp;gt; {
  const r = await client.query(
    \"UPDATE _prisma_migrations SET checksum = \$1 WHERE migration_name = \$2\",
    [\"&amp;lt;your_hash_here&amp;gt;\", \"20240101_something\"]
  );
  console.log(\"rows updated:\", r.rowCount);
  await client.end();
}).catch(e =&amp;gt; { console.error(e.message); client.end(); });
"'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Critical:&lt;/strong&gt; Always update ALL rows (no &lt;code&gt;rolled_back_at IS NULL&lt;/code&gt; filter). Prisma checks rolled-back rows too and will keep complaining if they have old checksums.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Case 3 — Already Applied (P3008)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Error:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The migration `20240101_something` is already recorded as applied in the database.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing to do — it's applied. If there's also a checksum mismatch, go to Case 2.&lt;/p&gt;




&lt;h2&gt;
  
  
  Case 4 — Cannot Roll Back, Not in Failed State (P3012)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Error:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Migration `20240101_something` cannot be rolled back because it is not in a failed state.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The migration is recorded as applied/success. Use Case 2 (checksum update) to reconcile the file change.&lt;/p&gt;




&lt;h2&gt;
  
  
  Case 5 — Shadow DB Error on Column That Doesn't Exist Yet (P3006)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Error:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Migration `20240101_fix` failed to apply cleanly to the shadow database.
ERROR: column "my_column" of relation "my_table" does not exist
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What's happening:&lt;/strong&gt; Prisma replays all migrations in timestamp order in the shadow DB. If migration A (timestamp &lt;code&gt;20240101&lt;/code&gt;) references a column that migration B (timestamp &lt;code&gt;20240115&lt;/code&gt;) creates, the shadow DB fails because A runs before B.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Move the offending SQL line from migration A into migration B (where the column actually gets created)&lt;/li&gt;
&lt;li&gt;Update checksums for both migration files using Case 2&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  SQL Rules for All Manual Migrations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Always use &lt;code&gt;IF EXISTS&lt;/code&gt; / &lt;code&gt;IF NOT EXISTS&lt;/code&gt; — make every migration idempotent
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Indexes&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"my_index"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"my_index"&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="nv"&gt;"my_table"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"my_column"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Columns&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"my_table"&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"my_column"&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Always use &lt;code&gt;CASCADE&lt;/code&gt; when dropping columns that have RLS policies
&lt;/h3&gt;

&lt;p&gt;PostgreSQL Row Level Security policies are tied to columns. Dropping the column without &lt;code&gt;CASCADE&lt;/code&gt; will fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- WRONG — will fail if RLS policies depend on tenant_id&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"my_table"&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="nv"&gt;"tenant_id"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- CORRECT — drops dependent RLS policies automatically&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"my_table"&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"tenant_id"&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Always wrap FK additions in a DO block
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;DO&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt; &lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_constraint&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;conname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'my_table_col_fkey'&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
    &lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"my_table"&lt;/span&gt;
      &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="nv"&gt;"my_table_col_fkey"&lt;/span&gt;
      &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"col"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="nv"&gt;"other_table"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Full Example: A Real Conflict Resolution
&lt;/h2&gt;

&lt;p&gt;Here's a real sequence we used to resolve a failed migration with RLS dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- migration.sql (fixed version)&lt;/span&gt;

&lt;span class="c1"&gt;-- DropIndex (already gone in DB — IF EXISTS makes this a no-op)&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"candidate_cv_tenant_id_candidate_id_idx"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"candidate_skills_tenant_id_candidate_id_skill_uri_idx"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Drop tenant_id (CASCADE removes dependent RLS policies automatically)&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"candidate_certifications"&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"tenant_id"&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"candidate_cv"&lt;/span&gt;             &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"tenant_id"&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"candidate_educations"&lt;/span&gt;     &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"tenant_id"&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"candidate_languages"&lt;/span&gt;      &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"tenant_id"&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"candidate_skills"&lt;/span&gt;         &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"tenant_id"&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;-- Change PK (idempotent: IF EXISTS on drop, unconditional on add)&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"candidate_embeddings"&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"candidate_embeddings_pkey"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"candidate_embeddings"&lt;/span&gt; &lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;COLUMN&lt;/span&gt; &lt;span class="nv"&gt;"tenant_id"&lt;/span&gt; &lt;span class="k"&gt;DROP&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"candidate_embeddings"&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="nv"&gt;"candidate_embeddings_pkey"&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"cand_id"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- CreateIndex&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"candidate_cv_candidate_id_idx"&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="nv"&gt;"candidate_cv"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"candidate_id"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;UNIQUE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="nv"&gt;"job_skills_unique_key"&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="nv"&gt;"job_skills"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"job_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"skill_id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;"tenant_id"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- AddForeignKey (guarded)&lt;/span&gt;
&lt;span class="k"&gt;DO&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt; &lt;span class="k"&gt;BEGIN&lt;/span&gt;
  &lt;span class="n"&gt;IF&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;EXISTS&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;pg_constraint&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;conname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'job_skills_tenant_id_fkey'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;THEN&lt;/span&gt;
    &lt;span class="k"&gt;ALTER&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="nv"&gt;"job_skills"&lt;/span&gt; &lt;span class="k"&gt;ADD&lt;/span&gt; &lt;span class="k"&gt;CONSTRAINT&lt;/span&gt; &lt;span class="nv"&gt;"job_skills_tenant_id_fkey"&lt;/span&gt;
      &lt;span class="k"&gt;FOREIGN&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"tenant_id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;REFERENCES&lt;/span&gt; &lt;span class="nv"&gt;"tenants"&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;DELETE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="k"&gt;UPDATE&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="n"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;END&lt;/span&gt; &lt;span class="err"&gt;$$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx prisma migrate resolve &lt;span class="nt"&gt;--rolled-back&lt;/span&gt; 20240101_fix_migration
npx prisma db execute &lt;span class="nt"&gt;--file&lt;/span&gt; prisma/migrations/20240101_fix_migration/migration.sql
npx prisma migrate resolve &lt;span class="nt"&gt;--applied&lt;/span&gt; 20240101_fix_migration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Quick Reference Cheat Sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;Cause&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;P3018&lt;/td&gt;
&lt;td&gt;Migration failed mid-run&lt;/td&gt;
&lt;td&gt;Fix SQL → &lt;code&gt;resolve --rolled-back&lt;/code&gt; → &lt;code&gt;db execute&lt;/code&gt; → &lt;code&gt;resolve --applied&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"modified after applied"&lt;/td&gt;
&lt;td&gt;Checksum mismatch&lt;/td&gt;
&lt;td&gt;Compute SHA-256 → update ALL rows in &lt;code&gt;_prisma_migrations&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P3008&lt;/td&gt;
&lt;td&gt;Already applied&lt;/td&gt;
&lt;td&gt;No-op (check for checksum mismatch too)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P3012&lt;/td&gt;
&lt;td&gt;Not in failed state&lt;/td&gt;
&lt;td&gt;Use checksum update approach&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P3006 shadow DB column missing&lt;/td&gt;
&lt;td&gt;Wrong timestamp order&lt;/td&gt;
&lt;td&gt;Move SQL to the migration that creates the column&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RLS policy dependency error&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;DROP COLUMN&lt;/code&gt; blocked by policy&lt;/td&gt;
&lt;td&gt;Add &lt;code&gt;CASCADE&lt;/code&gt; to &lt;code&gt;DROP COLUMN IF EXISTS&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FK constraint already exists&lt;/td&gt;
&lt;td&gt;Migration re-run&lt;/td&gt;
&lt;td&gt;Wrap FK in &lt;code&gt;DO $$ IF NOT EXISTS&lt;/code&gt; block&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Never &lt;code&gt;prisma migrate reset&lt;/code&gt;&lt;/strong&gt; — there's always a manual fix&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query the real DB first&lt;/strong&gt; before writing any SQL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;IF EXISTS&lt;/code&gt; / &lt;code&gt;IF NOT EXISTS&lt;/code&gt; everywhere&lt;/strong&gt; — idempotent migrations don't cause pain&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;CASCADE&lt;/code&gt; on &lt;code&gt;DROP COLUMN&lt;/code&gt;&lt;/strong&gt; if you use PostgreSQL RLS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wrap FKs in &lt;code&gt;DO $$ IF NOT EXISTS&lt;/code&gt; blocks&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checksum fix: update ALL rows&lt;/strong&gt;, not just the non-rolled-back one&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadow DB timestamp ordering&lt;/strong&gt;: move SQL to the migration where the column is born&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;Battle-tested on a production PostgreSQL database with RLS, pgbouncer, and Prisma Migrate.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>prisma</category>
      <category>postgres</category>
      <category>database</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
