Connect 4: Spot the Fake!
JavaScript (ES6),  202 194 187  183 bytes
Takes input as a matrix with \$2\$ for red, \$4\$ for yellow and \$0\$ for empty. Returns a string of 0-indexed moves (or an empty string if there's no solution). Reds start the game.

m=&gt;(p=[...'5555555'],g=(c,s=o='')=&gt;/2|4/.test(m)?['',0,2,4].some(n=&gt;m.join``.match(`(1|3)(.{1${n}}\\1){3}`))?o:p.map((y,x)=&gt;m[m[y][x]--^c||p[g(c^6,s+x,p[x]--),x]++,y][x]++)&amp;&amp;o:o=s)(2)

Try it online!
How?
The recursive function \$g\$ attempts to replace all \$2\$'s and \$4\$'s in the input matrix with \$1\$'s and \$3\$'s respectively.
While doing so, it makes sure that we don't have any run of four consecutive odd values until all even values have disappeared (i.e. if a side wins, it must be the last move).
The row \$y\$ of the next available slot for each column \$x\$ is stored in \$p[x]\$.
Commented
m =&gt; (                            // m[] = input matrix
  p = [...'5555555'],             // p[] = next row for each column
  g = (c,                         // g = recursive function taking c = color,
          s = o = '') =&gt;          //     s = current solution, o = final output
    /2|4/.test(m) ?               // if the matrix still contains at least a 2 or a 4:
      ['', 0, 2, 4]               //   see if we have four consecutive 1's or 3's
      .some(n =&gt;                  //   by testing the four possible directions
        m.join``                  //   on the joined matrix, using
        .match(                   //   a regular expression where the number of characters
          `(1|3)(.{1${n}}\\1){3}` //   between each occurrence is either 1, 10, 12 or 14
        )                         //   (horizontal, diagonal, vertical, anti-diagonal)
      ) ?                         //   if we have a match:
        o                         //     abort and just return the current value of o
      :                           //   else:
        p.map((y, x) =&gt;           //     for each cell at (x, y = p[x]):
          m[                      // 
            m[y][x]--             //       decrement the value of the cell
            ^ c ||                //       compare the original value with c
            p[                    //       if they're equal:
              g(                  //         do a recursive call with:
                c ^ 6,            //           the other color
                s + x,            //           the updated solution
                p[x]--            //           the updated row for this column
              ),                  //         end of recursive call
              x                   //         then:
            ]++,                  //         restore p[x]
            y                     //         and restore m[y][x]
          ][x]++                  //         to their initial values
        ) &amp;&amp; o                    //     end of map(); yield o
    :                             // else:
      o = s                       //   we've found a solution: copy s to o
)(2)                              // initial call to g() with c = 2