Summary
Bit's error handling and model classes rely on instanceof across package boundaries, which silently breaks whenever two copies of the defining package coexist in one process. Build capsules make this easy to hit: a capsule network routinely contains multiple copies of @teambit packages (different versions, or the same version from different generations — see #10583).
Concrete example
component-status-loader.ts classifies load failures:
} catch (err: any) {
if (err instanceof ComponentNotFoundInPath || err instanceof MissingBitMapComponent) {
if (componentFromModel) status.deleted = true;
...
When the loader that throws and the status loader that catches resolve ComponentNotFoundInPath from different copies, the instanceof is false and the error escapes as fatal. Observed effect (diagnosed on CI during #10582): a freshly tagged component with its directory present reported {deleted: true} / tolerant recovery paths (checkout reset, staged detection) turned into hard crashes.
Suggested direction
For error classes at least, match on a stable discriminator instead of (or in addition to) instanceof — e.g. err.name / a code property / BitError.isBitError(err, 'ComponentNotFoundInPath') helper — the same pattern Node ecosystem libraries use for exactly this reason. The status-loader catch above and its siblings (ComponentsPendingImport, etc.) are the highest-value call sites; a repo-wide sweep of instanceof <ErrorClass> on cross-package classes would find the rest.
Found while diagnosing #10583, where mixed-generation capsules made this class of failure deterministic. Fixing this would defang that bug's symptom independently of the lane fix.
🤖 Generated with Claude Code
Summary
Bit's error handling and model classes rely on
instanceofacross package boundaries, which silently breaks whenever two copies of the defining package coexist in one process. Build capsules make this easy to hit: a capsule network routinely contains multiple copies of@teambitpackages (different versions, or the same version from different generations — see #10583).Concrete example
component-status-loader.tsclassifies load failures:When the loader that throws and the status loader that catches resolve
ComponentNotFoundInPathfrom different copies, theinstanceofis false and the error escapes as fatal. Observed effect (diagnosed on CI during #10582): a freshly tagged component with its directory present reported{deleted: true}/ tolerant recovery paths (checkout reset, staged detection) turned into hard crashes.Suggested direction
For error classes at least, match on a stable discriminator instead of (or in addition to)
instanceof— e.g.err.name/ acodeproperty /BitError.isBitError(err, 'ComponentNotFoundInPath')helper — the same pattern Node ecosystem libraries use for exactly this reason. The status-loader catch above and its siblings (ComponentsPendingImport, etc.) are the highest-value call sites; a repo-wide sweep ofinstanceof <ErrorClass>on cross-package classes would find the rest.Found while diagnosing #10583, where mixed-generation capsules made this class of failure deterministic. Fixing this would defang that bug's symptom independently of the lane fix.
🤖 Generated with Claude Code