Magento 2 missing bin/magento, lib, dev and setup directories
If you’ve ever pulled a Magento 2 project and found bin/magento, lib/, dev/ or setup/ simply aren’t there, you’re not going crazy - those directories are deployed out of the magento/magento2-base package by Composer rather than living in the repo. When that deploy step doesn’t run, or runs partially, the files never land and you’re left staring at a project that looks half-installed.
The fix
In most cases a reinstall of the base package re-triggers the deploy and the missing directories reappear:
composer reinstall magento/magento2-baseThat forces Composer to remove and re-add the package, which runs the magento-composer-installer deploy step again and copies the mapped files back into place. Worth running bin/magento afterwards to confirm the CLI is back.
Why it happens
The deploy is handled by magento/magento-composer-installer, and there’s a fairly nasty bug in its copy strategy. The Copy::createDelegate() method uses file_exists(), which dereferences symlinks - so when a symlink with a missing target sits at one of the mapped destination paths, the installer reads it as absent, tries to mkdir() over the existing link node and hits a silent File exists error.
The worse part is the error swallowing. DeployManager::doDeploy() catches the ErrorException but only logs it under -vvv verbosity, so the remaining mappings get skipped with no warning. The install reports success while setup/ and friends are partially or completely empty.
I’ve raised a Github issue with the full reproduction. There’s also a longstanding PR against magento-composer-installer that removes the exception suppression so composer install fails loud and early instead of leaving you with a broken-but-apparently-fine install - it’s been open for years awaiting review.
So if the reinstall doesn’t stick, check for a dangling symlink at the target paths before assuming Composer is at fault.