ruvnet/ruflo · critical
Dependency validation failed: ${errorMessages}
Error message
Dependency validation failed:
${errorMessages} What it means
Thrown by EnhancedPluginRegistry.initialize() when the dependency graph validation reports critical errors. dependencyGraph.validate() walks every registered plugin's parsed metadata.dependencies and reports problems (missing dependencies, cycles, bad ranges); entries of type 'missing' whose declaration is optional are filtered out, and any remaining error messages are joined into this aggregate error before any plugin actually initializes.
Source
Thrown at v3/@claude-flow/plugins/src/registry/enhanced-plugin-registry.ts:399
// =========================================================================
// Initialization
// =========================================================================
/**
* Initialize all registered plugins.
*/
async initialize(): Promise<void> {
if (this.initialized) {
throw new Error('Registry already initialized');
}
// Validate dependencies
const errors = this.dependencyGraph.validate();
const criticalErrors = errors.filter(e => e.type !== 'missing' || !this.isOptionalDependency(e));
if (criticalErrors.length > 0) {
const errorMessages = criticalErrors.map(e => e.message).join('\n');
throw new Error(`Dependency validation failed:\n${errorMessages}`);
}
// Initialize based on strategy
const strategy = this.config.initializationStrategy ?? 'sequential';
switch (strategy) {
case 'sequential':
await this.initializeSequential();
break;
case 'parallel':
await this.initializeParallel();
break;
case 'parallel-safe':
await this.initializeParallelSafe();
break;
}
// Check for initialization errors (including conflicts)View on GitHub (pinned to fa13ee4ad6)
Solutions
- Read each 'name: message' line in the error - it names the missing/circular/incompatible dependency per plugin
- Register the missing dependency plugin (at a satisfying version) before initialize()
- Break dependency cycles by extracting the shared piece into a third plugin both depend on
- Declare truly optional dependencies in the optional form so 'missing' does not become critical
Example fix
// before await registry.register(aPlugin); // aPlugin depends on 'utils^2.0.0' await registry.initialize(); // throws: Dependency validation failed ... missing utils // after await registry.register(utilsPluginV2); // name 'utils', version 2.1.0 await registry.register(aPlugin); await registry.initialize();
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight the same check initialize() performs, without throwing
const errors = validatePluginDependencyGraph(registeredPlugins); // mirror of dependencyGraph.validate()
const critical = errors.filter(e => e.type !== 'missing' || !isOptionalDeclaration(e));
if (critical.length > 0) {
// names the missing/cyclic deps before initialize() runs
reportAndAbort(critical);
} Try / catch
try {
await registry.initialize();
} catch (err) {
if (err instanceof Error && err.message.startsWith('Dependency validation failed')) {
// each line is 'plugin: message' - drive a targeted fix or report
const issues = err.message.split('\n').slice(1);
await reportPluginIssues(issues);
}
throw err;
} Prevention
- Register every plugin your others declare in metadata.dependencies before initialize()
- Declare truly optional dependencies as optional so a missing dep does not block boot
- Keep dependency version ranges in sync with the versions you actually register
- Avoid mutual dependencies between two plugins; extract shared code into a third plugin
When it happens
Trigger: Registering plugin A that depends on 'b^1.0.0' while 'b' is not registered (and not declared optional); two plugins depending on each other, forming a cycle; a dependency version range that does not match the registered version (e.g. 'utils^2.0.0' vs registered 'utils' 1.4.0).
Common situations: Forgetting to register a shared dependency plugin in the bootstrap list; upgrading one plugin's dependency range without upgrading the dependency plugin; circular imports between two plugins; optional dependencies declared as plain strings instead of the optional form so they are treated as required.
Related errors
- Cannot remove ${name}: required by ${dependents.join(', ')}
- Invalid plugin: does not implement IPlugin interface
- Plugin ${name} already registered
- Maximum plugin limit (${this.config.maxPlugins}) reached
- Plugin ${name} requires core version >= ${resolvedPlugin.met
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/e58017f7a00d9d62.
Report an issue: GitHub.