pbakaus/impeccable · error
concept-seed: --grain must be one of ${COMPOSITION_GRAINS.jo
Error message
concept-seed: --grain must be one of ${COMPOSITION_GRAINS.join(', ')} What it means
Thrown when --grain is provided but is not one of COMPOSITION_GRAINS: product, flow, view, region. Grain names how much of the product is in play (a whole site vs. a flow vs. one view vs. a region), and only those four values are cataloged. null/undefined means no grain preference and is allowed.
Source
Thrown at plugin/skills/impeccable/scripts/concept-seed.mjs:327
if (!Number.isInteger(reroll) || reroll < 0) {
throw new Error('concept-seed: --reroll must be a non-negative integer');
}
if (register !== null && register !== 'safer' && register !== 'bolder') {
throw new Error('concept-seed: --register must be safer or bolder');
}
if (register !== null && reroll < 1) {
throw new Error('concept-seed: --register steers a re-roll round; pass --reroll <n> with it');
}
if (register !== null && scope !== 'direction') {
throw new Error('concept-seed: --register applies to direction rounds only');
}
if (mode !== null && !SEED_MODES.has(mode)) {
throw new Error('concept-seed: --mode must be persuade, operate, read, or experience');
}
// Grain needs no mode: how much of the product is in play is independent of
// which register of work it is.
if (grain !== null && !COMPOSITION_GRAINS.includes(grain)) {
throw new Error(`concept-seed: --grain must be one of ${COMPOSITION_GRAINS.join(', ')}`);
}
if (platform !== null && !COMPOSITION_PLATFORMS.includes(platform)) {
throw new Error(`concept-seed: --platform must be one of ${COMPOSITION_PLATFORMS.join(', ')}`);
}
if (!Number.isInteger(candidateCount) || candidateCount < 5 || candidateCount > 7) {
throw new Error('concept-seed: --candidate-count must be an integer from 5 to 7');
}
const unit = (salt) => {
const h = crypto.createHash('sha256').update(`${scope}:${salt}:${key}`).digest();
return h.readUInt32BE(0) / 0xffffffff;
};
const indexSalt = reroll === 0 ? 'index' : `index:reroll-${reroll}`;
const buildIndex = 3 + Math.floor(unit(indexSalt) * (candidateCount - 2)); // 3..candidateCount
// Surface scope deals a hand of three grounded structures: one card is not
// a choice, and the full ranked list would hand selection back to the
// model's taste. The dice pick all three; the primary index leads. The
// no-lineup rule stays direction-only, where it was written for worlds.
const dealtIndices = [buildIndex];View on GitHub (pinned to d14711ae3d)
Solutions
- Use exactly one of: --grain product, --grain flow, --grain view, --grain region.
- Omit --grain to deal compositions without a grain preference.
Example fix
# before $ node concept-seed.mjs --scope surface --grain section ... # after $ node concept-seed.mjs --scope surface --grain region ...
Defensive patterns
Strategy: validation
Validate before calling
const COMPOSITION_GRAINS = ['product', 'flow', 'view', 'region'];
if (grain != null && !COMPOSITION_GRAINS.includes(grain)) {
throw new Error(`--grain must be one of: ${COMPOSITION_GRAINS.join(', ')}`);
} Type guard
function isValidGrain(value) {
return value == null || ['product','flow','view','region'].includes(value);
} Try / catch
try {
await seedConcepts({ scope, grain });
} catch (err) {
if (/--grain must be one of/.test(err.message)) {
console.error('Use --grain product|flow|view|region, or omit it.');
} else throw err;
} Prevention
- Parse --grain as an enum; reject near-synonyms (section/page) at the CLI.
- Share the COMPOSITION_GRAINS constant between CLI, seeder, and catalog validator.
- Document that grain is optional and means 'no preference' when omitted.
When it happens
Trigger: Passing --grain with a value like 'page', 'section', 'component', 'app', 'screen' — none are valid. The check is grain !== null && !COMPOSITION_GRAINS.includes(grain).
Common situations: CLI typo; using a near-synonym ('section' instead of 'region', 'page' instead of 'view'); a UI exposing free-text grain.
Related errors
- concept-seed: --scope must be direction or surface
- concept-seed: --reroll must be a non-negative integer
- concept-seed: --register must be safer or bolder
- concept-seed: --register steers a re-roll round; pass --rero
- concept-seed: --register applies to direction rounds only
AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13).
Data as JSON: /api/errors/268adfd5bf7a92fe.
Report an issue: GitHub.