ruvnet/ruflo · error
RuvllmConfig.modelsDir is required
Error message
RuvllmConfig.modelsDir is required
What it means
RuvllmBridge's constructor validates that config.modelsDir is truthy before merging with DEFAULT_CONFIG (whose defaults do not include modelsDir), throwing immediately on `new RuvllmBridge(config)` or the first `getRuvllmBridge(config)`. It is a fail-fast guard so an unconfigured bridge never reaches the model-directory scan with no directory to scan.
Solutions
- Pass a concrete directory: getRuvllmBridge({ modelsDir: '/path/to/gguf/models' })
- If sourced from env, fail fast when unset rather than passing undefined
- Default to a stable location such as path.join(os.homedir(), '.claude-flow', 'models') and mkdir it first
- Ensure the value is a non-empty string — undefined and '' both throw
Example fix
// before
const bridge = getRuvllmBridge({ modelsDir: process.env.MODELS_DIR }); // undefined → throws
// after
const modelsDir = process.env.MODELS_DIR ?? path.join(os.homedir(), '.claude-flow', 'models');
await fs.mkdir(modelsDir, { recursive: true });
const bridge = getRuvllmBridge({ modelsDir }); Defensive patterns
Strategy: validation
Validate before calling
import { mkdir } from 'node:fs/promises';
import os from 'node:os';
const modelsDir = process.env.MODELS_DIR ?? `${os.homedir()}/.claude-flow/models`;
if (typeof modelsDir !== 'string' || modelsDir.length === 0) {
throw new Error('Set MODELS_DIR (or pass modelsDir) before starting the appliance');
}
await mkdir(modelsDir, { recursive: true });
const bridge = getRuvllmBridge({ modelsDir }); Type guard
function isValidRuvllmConfig(c: unknown): c is RuvllmConfig {
return (
typeof c === 'object' &&
c !== null &&
typeof (c as RuvllmConfig).modelsDir === 'string' &&
(c as RuvllmConfig).modelsDir.length > 0
);
} Prevention
- Resolve modelsDir once at boot (env var or explicit path) and pass it to the first getRuvllmBridge call
- Add a startup assertion for env-derived config so a missing variable fails before the bridge is constructed
- Never pass process.env.X through unvalidated — undefined becomes a constructor throw
When it happens
Trigger: `new RuvllmBridge({})`; `getRuvllmBridge()` with no prior configured call; passing `modelsDir: process.env.MODELS_DIR` when MODELS_DIR is undefined; passing an empty string as modelsDir.
Common situations: Building the bridge before application config loads; env var name typo (MODELS_DIR vs MODELSDIR); CI where the variable is not exported; tests constructing the bridge without a fixture directory.
Understand the failure class
Background: "X is required", "must be set", "cannot be empty": the missing-required-config error family, from Vertex AI project/location to WeChat keys — this error's family across 18 libraries.
Related errors
- anchor task has no query
- anchor task requires non-empty string labels
- Dangerous key segment rejected
- Dual-mode config must export a workers array
- flywheel anchor manifest requires path and sha256
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/b5c4e2d01fc78e81.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/appliance/ruvllm-bridge.ts:135
if (LOW.has(w)) score -= 0.1;
}
return Math.max(0, Math.min(1, score + Math.min(0.2, words.length / 200)));
}
// ── Bridge ──────────────────────────────────────────────────
export class RuvllmBridge {
private config: Required<RuvllmConfig>;
private models: Map<string, ModelInfo> = new Map();
private activeModel: string | null = null;
private kvCacheEntries = 0;
private ruvectorCore: any = null;
private ruvectorRouter: any = null;
private ruvectorSona: any = null;
private ggufEngine: GgufEngineType | null = null;
constructor(config: RuvllmConfig) {
if (!config.modelsDir) throw new Error('RuvllmConfig.modelsDir is required');
this.config = { ...DEFAULT_CONFIG, ...config };
}
/** Probe optional @ruvector packages, initialize GGUF engine, and scan modelsDir. */
async initialize(): Promise<void> {
this.ruvectorCore = await this.tryImport('@ruvector/core');
this.ruvectorRouter = await this.tryImport('@ruvector/router');
this.ruvectorSona = await this.tryImport('@ruvector/sona');
// Initialize GGUF engine for local model inference
try {
const { GgufEngine } = await import('./gguf-engine.js');
this.ggufEngine = new GgufEngine({
contextSize: this.config.contextSize,
maxTokens: this.config.maxTokens,
temperature: this.config.temperature,
kvCachePath: this.config.kvCachePath,
verbose: this.config.verbose,View on GitHub (pinned to fa13ee4ad6)