TheAlgorithms/Python · error · ValueError

{not_in_genes_list} is not in genes list, evolution cannot c

Error message

{not_in_genes_list} is not in genes list, evolution cannot converge

What it means

Raised by basic() in genetic_algorithm/basic_string.py when the target string contains characters absent from the genes list. The algorithm builds every candidate solely from random.choice(genes); if the target needs a character the population can never produce, mutation can never converge and the loop would run forever — so the function aborts with the exact missing characters in the message.

Source

Thrown at genetic_algorithm/basic_string.py:130

    Traceback (most recent call last):
        ...
    ValueError: ['e', 's'] is not in genes list, evolution cannot converge
    >>> genes.remove("t")
    >>> basic("test", genes)
    Traceback (most recent call last):
        ...
    ValueError: ['e', 's', 't'] is not in genes list, evolution cannot converge
    """

    # Verify if N_POPULATION is bigger than N_SELECTED
    if N_POPULATION < N_SELECTED:
        msg = f"{N_POPULATION} must be bigger than {N_SELECTED}"
        raise ValueError(msg)
    # Verify that the target contains no genes besides the ones inside genes variable.
    not_in_genes_list = sorted({c for c in target if c not in genes})
    if not_in_genes_list:
        msg = f"{not_in_genes_list} is not in genes list, evolution cannot converge"
        raise ValueError(msg)

    # Generate random starting population.
    population = []
    for _ in range(N_POPULATION):
        population.append("".join([random.choice(genes) for i in range(len(target))]))

    # Just some logs to know what the algorithms is doing.
    generation, total_population = 0, 0

    # This loop will end when we find a perfect match for our target.
    while True:
        generation += 1
        total_population += len(population)

        # Random population created. Now it's time to evaluate.

        # (Option 1) Adding a bit of concurrency can make everything faster,
        #

View on GitHub (pinned to f5988cc097)

Solutions

  1. Include every character of the target in genes, e.g. genes = set(ascii_letters) | set(target) or a charset known to cover the target.
  2. Or sanitize the target to the gene alphabet before calling.
  3. Check the message — it names exactly which characters are missing.

Example fix

# before
import string
basic('hello world 42', string.ascii_letters)  # space and digits missing

# after
genes = set(string.ascii_letters + string.digits + ' ')
basic('hello world 42', genes)
Defensive patterns

Strategy: validation

Validate before calling

missing = {c for c in target if c not in genes}
if missing:
    raise ValueError(f'target uses characters outside genes: {sorted(missing)}')
basic(target, genes)

Type guard

def target_is_reachable(target: str, genes) -> bool:
    return all(c in genes for c in target)

Try / catch

try:
    basic(target, genes)
except ValueError as exc:
    if 'not in genes list' in str(exc):
        genes = set(genes) | set(target)  # widen gene pool
        basic(target, genes)
    else:
        raise

Prevention

When it happens

Trigger: Calling basic('test', genes) after genes.remove('t') — the message lists ['e', 's', 't'] or the subset actually missing. Any target/genes mismatch triggers it: digits in the target with letter-only genes, accented characters, or a space not included in genes.

Common situations: Building genes from string.ascii_letters but targeting a string containing digits, spaces, or punctuation; locale-specific characters (accented letters) missing from ASCII gene sets; whitespace stripped from a gene string by overzealous cleanup.

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/ddc58074271a07e9. Report an issue: GitHub.