nikivdev/code · error

insert failed

Error message

insert failed: {:?}

What it means

insert_task_run persists a task-run record into the groove database by building a raw SQL string and executing it. When db.execute fails, the underlying error is wrapped as "insert failed: {:?}". The most common root cause is sql_escape, which replaces single quotes with backticks instead of proper escaping, so values containing backticks, percent signs, or overly long content can still break the SQL.

Solutions

  1. Inspect the wrapped inner error with RUST_BACKTRACE=1 to see the actual DB error
  2. Check the task output/content being inserted for backticks or odd characters that sql_escape mishandles
  3. Verify the task_runs table exists and matches the columns in the INSERT
  4. Confirm the database file/connection is writable and not locked

Example fix

// before
value.replace('\'', "`").replace('\0', "")
// after
// double the quotes instead of substituting backticks, if the backend supports ''
value.replace('\'', "''").replace('\0', "")
Defensive patterns

Strategy: try-catch

Validate before calling

// before insert
fn validate_output(output: &str) -> Result<(), String> {
    if output.contains('`') || output.len() > 1_000_000 {
        Err("output contains characters/size that may break the insert".into())
    } else { Ok(()) }
}

Try / catch

match record_task_run(&record) {
    Err(e) if e.to_string().contains("insert failed") => {
        eprintln!("DB insert failed, retrying with sanitized output: {e:#}");
        // retry with sanitized/truncated output
    }
    Err(e) => return Err(e),
    Ok(()) => {}
}

Prevention

When it happens

Trigger: record_task_run calls insert_task_run and db.execute(&sql) returns Err — e.g. the SQL text is malformed after escaping, the output/fields contain characters that break the statement, the table doesn't exist, or the database file/connection is unavailable.

Common situations: Task output contains backticks or control characters that survive sql_escape and corrupt the statement; schema drift after a version change so the task_runs table/columns are missing; database locked or on read-only media.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/6192d6e01a4e12cf. Report an issue: GitHub.

Appendix: source

Thrown at src/jazz_state.rs:202

        VALUES ('{}', {}, '{}', '{}', '{}', '{}', {}, {}, {}, {}, '{}', {}, '{}')",
        sql_escape(&record.project_root),
        project_name,
        sql_escape(&record.config_path),
        sql_escape(&record.task_name),
        sql_escape(&record.command),
        sql_escape(&record.user_input),
        if record.success { "true" } else { "false" },
        status,
        duration_ms,
        timestamp_ms,
        sql_escape(&record.flow_version),
        if record.used_flox { "true" } else { "false" },
        sql_escape(&output),
    );

    db.execute(&sql)
        .map(|_| ())
        .map_err(|err| anyhow::anyhow!("insert failed: {:?}", err))
}

fn sql_escape(value: &str) -> String {
    // Replace single quotes with backticks since groove SQL doesn't handle '' escaping well
    // Also remove null bytes
    value.replace('\'', "`").replace('\0', "")
}

fn truncate_output(value: &str, limit: usize) -> String {
    if value.len() <= limit {
        return value.to_string();
    }

    let mut start = value.len() - limit;
    while start < value.len() && !value.is_char_boundary(start) {
        start += 1;
    }

View on GitHub (pinned to a747e741ae)