nanocoai/nanoclaw · error

Invalid template ref: "${ref}"

Error message

Invalid template ref: "${ref}"

What it means

resolveLocalTemplate validates the user-supplied template ref before resolving it against the templates directory. This variant throws when the ref is empty or has leading/trailing whitespace — refs must be exact, non-empty relative names. (A separate error covers absolute paths and '~', and another covers escaping.)

Source

Thrown at src/templates/local-dir.ts:19

import fs from 'fs';
import path from 'path';

import { TEMPLATES_DIR } from '../config.js';

/**
 * Resolve a LOCAL template ref to an absolute directory under `base`
 * (TEMPLATES_DIR by default). Lexical containment only — no realpathSync, no
 * symlink resolution (out of threat model). Mirrors ensureWithinBase() in
 * group-folder.ts. Refs are legitimately multi-segment (e.g. "sales/sdr"), so
 * this does NOT reuse isValidGroupFolder (which rejects "/").
 *
 * Rejects: empty / untrimmed refs, absolute paths, a leading "~", and any ref
 * that escapes `base` after resolution. Throws if the resolved path is missing
 * or not a directory.
 */
export function resolveLocalTemplate(ref: string, base: string = TEMPLATES_DIR): string {
  if (!ref || ref !== ref.trim()) {
    throw new Error(`Invalid template ref: "${ref}"`);
  }
  if (path.isAbsolute(ref) || ref.startsWith('~')) {
    throw new Error(`Template ref must be relative to the templates directory: "${ref}"`);
  }
  const candidate = path.resolve(base, ref);
  const rel = path.relative(base, candidate);
  if (rel.startsWith('..') || path.isAbsolute(rel)) {
    throw new Error(`Template ref escapes the templates directory: "${ref}"`);
  }
  if (!fs.existsSync(candidate) || !fs.statSync(candidate).isDirectory()) {
    throw new Error(`Template not found: "${ref}" (looked in ${base})`);
  }
  return candidate;
}

View on GitHub (pinned to 294ef2aee8)

Solutions

  1. Trim before calling: resolveLocalTemplate(ref.trim()).
  2. Validate the ref is non-empty after trimming and surface a friendly CLI error first.
  3. Sanitize template lists in config so they contain no blank entries.

Example fix

// before
resolveLocalTemplate(rawArg);

// after
resolveLocalTemplate(rawArg?.trim() ?? '').
Defensive patterns

Strategy: validation

Validate before calling

const ref = rawRef?.trim() ?? '';
if (!ref) throw new Error('template ref required');
if (!/^[a-z0-9][a-z0-9._/-]*$/i.test(ref)) throw new Error(`bad template ref: "${ref}"`);

Type guard

const isValidTemplateRef = (r: unknown): r is string => typeof r === 'string' && r.length > 0 && r === r.trim() && !r.startsWith('/') && !r.startsWith('~');

Prevention

When it happens

Trigger: Calling with ref = '', ' basic-agent ', or a value built from untrimmed user input (CLI arg, config field) that carries whitespace; also undefined/null coerced to a string.

Common situations: Passing a template name straight from a config file or CLI argument without trimming; copy-pasting a template name with a trailing newline from a list; template lists containing an empty entry.

Related errors


AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28). Data as JSON: /api/errors/adc5b752ea372683. Report an issue: GitHub.