ruvnet/RuView · error · TypeError
guidance repoRoot must be a string or null
Error message
guidance repoRoot must be a string or null
What it means
getGuidance options.repoRoot accepts only undefined, null, or a string (the repo root used for source-citation checks). Any other type — number, boolean, object, URL instance — throws this TypeError.
Source
Thrown at harness/ruview/src/guidance.js:357
*/
export function getGuidance(input = {}, options = {}) {
if (!input || typeof input !== 'object' || Array.isArray(input)) {
throw new TypeError('guidance input must be an object');
}
if (!options || typeof options !== 'object' || Array.isArray(options)) {
throw new TypeError('guidance options must be an object');
}
if (input.topic !== undefined && typeof input.topic !== 'string') {
throw new TypeError('guidance topic must be a string');
}
if (input.query !== undefined && typeof input.query !== 'string') {
throw new TypeError('guidance query must be a string');
}
if (input.limit !== undefined && (typeof input.limit !== 'number' || !Number.isFinite(input.limit))) {
throw new TypeError('guidance limit must be a finite number');
}
if (options.repoRoot !== undefined && options.repoRoot !== null && typeof options.repoRoot !== 'string') {
throw new TypeError('guidance repoRoot must be a string or null');
}
const topic = input.topic === undefined ? 'overview' : input.topic;
if (!GUIDANCE_TOPICS.includes(topic)) {
throw new RangeError(`unsupported guidance topic: ${topic}`);
}
const query = input.query === undefined ? '' : input.query.trim();
if (query && (query.length < 2 || query.length > 500)) {
throw new RangeError('guidance query must contain 2..500 characters');
}
const rawLimit = input.limit === undefined ? 20 : input.limit;
if (!Number.isFinite(rawLimit) || rawLimit < 1 || rawLimit > 20) {
throw new RangeError('guidance limit must be between 1 and 20');
}
const limit = Math.floor(rawLimit);
const wanted = tokenize(query);
const candidates = CAPABILITIES
.filter((capability) => topic === 'overview' || capability.topics.includes(topic))
.map((capability, order) => ({ capability, order, score: scoreCapability(capability, wanted) }))View on GitHub (pinned to 4685618388)
Solutions
- Pass an absolute path string or null: getGuidance(input, { repoRoot: process.cwd() }).
- Convert URL objects first: repoRoot: fileURLToPath(new URL('../..', import.meta.url)).
- Use null explicitly when you want guidance without repo-derived source checks.
Example fix
// before
getGuidance({}, { repoRoot: false })
// after
getGuidance({}, { repoRoot: null }) // or an absolute path string like '/repos/RuView' Defensive patterns
Strategy: type-guard
Validate before calling
const repoRoot = rawRepoRoot === undefined || rawRepoRoot === null
? null
: String(rawRepoRoot);
getGuidance(input, { repoRoot }); Type guard
function isValidRepoRoot(v) {
return v === undefined || v === null || typeof v === 'string';
} Try / catch
try {
getGuidance(input, { repoRoot });
} catch (e) {
if (e instanceof TypeError && e.message === 'guidance repoRoot must be a string or null') {
return getGuidance(input, { repoRoot: null });
}
throw e;
} Prevention
- Convert URL/path objects with fileURLToPath()/toString() before passing.
- Use null (not 0/false) to express 'no repo root'.
- Keep repoRoot as an absolute path string from process.cwd() or realpathSync.
When it happens
Trigger: getGuidance({}, { repoRoot: 0 }), { repoRoot: false }, { repoRoot: new URL('file:///repo') }, or passing a path object from a path library instead of path.toString().
Common situations: Using 0/false as 'no root' sentinels (this API wants null/undefined); fileURLToPath forgotten when converting import.meta.url; a path library returning objects (path-object, pathy).
Related errors
- guidance input must be an object
- guidance options must be an object
- guidance topic must be a string
- guidance query must be a string
- guidance limit must be a finite number
AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16).
Data as JSON: /api/errors/c139853f00f2482c.
Report an issue: GitHub.