David Spillett have explained the root of problem and the way to solving in his answer.
Alternatively, if you want to use product_id without table alias by some exotic reason, you may use USING in joining which collapses joining columns into one column:
SELECT `main_table`.*
FROM `wishlist_item` AS `main_table`
INNER JOIN `cataloginventory_stock_status` AS `stockItem` USING (product_id)
INNER JOIN `catalog_category_product_index_store1` AS `cat_index` USING (product_id)
WHERE (`wishlist_id` = '1')
AND (`main_table`.`store_id` IN('1'))
AND stockItem.stock_status = 1
AND cat_index.category_id = '2'
AND cat_index.visibility IN (3, 2, 4)
ORDER BY find_in_set(product_id,'1,2,3'), name ASC
LIMIT 12
Also you may replace an asterisk in output list with separate columns list - in this case the column name in ORDER BY will be treated as output column alias (if this column name exists in output columnset, of course):
SELECT `main_table`.column1, ... , main_table.product_id, ...
FROM `wishlist_item` AS `main_table`
INNER JOIN `cataloginventory_stock_status` AS `stockItem`
ON stockItem.product_id = main_table.product_id
AND stockItem.stock_status = 1
INNER JOIN `catalog_category_product_index_store1` AS `cat_index`
ON cat_index.product_id = main_table.product_id
AND cat_index.category_id = '2'
AND cat_index.visibility IN (3, 2, 4)
WHERE (`wishlist_id` = '1')
AND (`main_table`.`store_id` IN('1'))
ORDER BY find_in_set(product_id,'1,2,3'), name ASC
LIMIT 12