ruvnet/ruflo · error · Error

Unknown template preset: ${template}. Use: ${Object.keys(pre

Error message

Unknown template preset: ${template}. Use: ${Object.keys(presets).join(', ')}

What it means

When formatChatTemplate is given a string template, it looks it up in a fixed preset map with exactly five keys: llama3, mistral, chatml, phi, gemma. An unrecognized string throws synchronously, listing the valid keys in the message. The check runs before any WASM template object is constructed, so no resource is allocated on failure.

Source

Thrown at v3/@claude-flow/cli/src/ruvector/ruvllm-wasm.ts:347

export async function formatChat(
  messages: ChatMessage[],
  template: TemplatePreset | { custom: string } | { modelId: string },
): Promise<string> {
  await initRuvllmWasm();
  const mod = await import('@ruvector/ruvllm-wasm');

  // Build template
  let tmpl: any;
  if (typeof template === 'string') {
    const presets: Record<string, () => any> = {
      llama3: () => mod.ChatTemplateWasm.llama3(),
      mistral: () => mod.ChatTemplateWasm.mistral(),
      chatml: () => mod.ChatTemplateWasm.chatml(),
      phi: () => mod.ChatTemplateWasm.phi(),
      gemma: () => mod.ChatTemplateWasm.gemma(),
    };
    const factory = presets[template];
    if (!factory) throw new Error(`Unknown template preset: ${template}. Use: ${Object.keys(presets).join(', ')}`);
    tmpl = factory();
  } else if ('custom' in template) {
    tmpl = mod.ChatTemplateWasm.custom(template.custom);
  } else if ('modelId' in template) {
    tmpl = mod.ChatTemplateWasm.detectFromModelId(template.modelId);
  }

  // Build messages
  const wasmMessages = messages.map(m => {
    switch (m.role) {
      case 'system': return mod.ChatMessageWasm.system(m.content);
      case 'user': return mod.ChatMessageWasm.user(m.content);
      case 'assistant': return mod.ChatMessageWasm.assistant(m.content);
      default: throw new Error(`Unknown role: ${m.role}`);
    }
  });

  return tmpl.format(wasmMessages);

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Use one of the five presets exactly: llama3, mistral, chatml, phi, gemma (lowercase, no version suffix).
  2. If your model is not in the preset list, pass { custom: '<jinja-template>' } or { modelId: '<hf-id>' } instead of a string.
  3. Guard the input: validate against the preset list before calling, and surface the allowed names to the user.

Example fix

// before
const out = buildTemplate('llama', messages); // typo, throws

// after: use the exact preset, or detect from model id
const out = buildTemplate('llama3', messages);
// or:
const out = buildTemplate({ modelId: 'meta-llama/Meta-Llama-3-8B-Instruct' }, messages);
Defensive patterns

Strategy: type-guard

Validate before calling

const TEMPLATE_PRESETS = ['llama3', 'mistral', 'chatml', 'phi', 'gemma'] as const;
type TemplatePreset = typeof TEMPLATE_PRESETS[number];

function isPreset(s: string): s is TemplatePreset {
  return (TEMPLATE_PRESETS as readonly string[]).includes(s);
}

Type guard

function resolveTemplate(t: string | { custom: string } | { modelId: string }) {
  if (typeof t === 'string') {
    if (!isPreset(t)) throw new Error(`Unknown template preset: ${t}. Use: ${TEMPLATE_PRESETS.join(', ')}`);
    return t;
  }
  return t;
}

Prevention

When it happens

Trigger: Calling the chat-template builder with template='llama' (typo of llama3), 'llama-3', 'gpt-4', 'qwen', 'vicuna', or any casing variant like 'Mistral'. Also when passing a model nickname that is not one of the five supported presets.

Common situations: Copy-pasting a HuggingFace model id (e.g. 'meta-llama/Meta-Llama-3-8B') into the template field instead of the preset name; version drift where a newer @ruvector/ruvllm-wasm exposes more presets than this wrapper maps; UI/CLI that forwards a user-typed model name verbatim.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/5aeee626f3eae8eb. Report an issue: GitHub.