mattermost-community/focalboard · error

getBlockHistoryNewestChildren unable to generate sql: %w

Error message

getBlockHistoryNewestChildren unable to generate sql: %w

What it means

The final (outer) history query failed at squirrel's ToSql() stage, so no SQL string could be generated for the blocks_history join query. Like error 92 but on the main query instead of the subquery; it is returned before any database round trip.

Source

Thrown at server/services/store/sqlstore/blocks.go:712

	}

	query := s.getQueryBuilder(db).
		Select(s.blockFields("bh")...).
		From(s.tablePrefix+"blocks_history AS bh").
		InnerJoin("("+subQuery+") AS sub ON bh.id=sub.id AND bh.insert_at=sub.max_insert_at", subArgs...)

	if opts.Page != 0 {
		query = query.Offset(uint64(opts.Page * opts.PerPage))
	}

	if opts.PerPage > 0 {
		// limit+1 to detect if more records available
		query = query.Limit(uint64(opts.PerPage + 1))
	}

	sql, args, err := query.ToSql()
	if err != nil {
		return nil, false, fmt.Errorf("getBlockHistoryNewestChildren unable to generate sql: %w", err)
	}

	// if we're using postgres or sqlite, we need to replace the
	// question mark placeholder with the numbered dollar one, now
	// that the full query is built
	if s.dbType == model.PostgresDBType || s.dbType == model.SqliteDBType {
		var rErr error
		sql, rErr = sq.Dollar.ReplacePlaceholders(sql)
		if rErr != nil {
			return nil, false, fmt.Errorf("getBlockHistoryNewestChildren unable to replace sql placeholders: %w", rErr)
		}
	}

	rows, err := db.Query(sql, args...)
	if err != nil {
		s.logger.Error(`getBlockHistoryNewestChildren ERROR`, mlog.Err(err))
		return nil, false, err
	}

View on GitHub (pinned to a84bbb65e3)

Solutions

  1. Inspect the wrapped err for the exact squirrel failure
  2. Validate opts.PerPage is > 0 before calling (or that the store clamps it)
  3. If building limits yourself, ensure uint64 conversion doesn't wrap a negative value
  4. Check for recent modifications to the query construction (Select/Join/Limit order)

Example fix

// before
opts.PerPage = 0 // becomes Limit(1)? or invalid
hist, _, err := store.GetBlockHistoryNewestChildren(id, opts)
// after
if opts.PerPage <= 0 {
    opts.PerPage = store.BlockHistoryDefaultPerPage
}
hist, _, err := store.GetBlockHistoryNewestChildren(id, opts)
Defensive patterns

Strategy: validation

Validate before calling

if opts.PerPage <= 0 {
    opts.PerPage = store.BlockHistoryDefaultPerPage
}
// then call GetBlockHistoryNewestChildren

Try / catch

hist, hasMore, err := store.GetBlockHistoryNewestChildren(blockID, opts)
if err != nil && strings.Contains(err.Error(), "unable to generate sql") {
    log.Printf("history query build failed for %s: %v", blockID, err)
    return fallbackHistoryFetch(blockID, opts)
}

Prevention

When it happens

Trigger: GetBlockHistoryNewestChildren with opts that make the outer query unrenderable — typically PerPage<=0 leading to query.Limit(uint64(opts.PerPage+1)) with an invalid/negative limit, or a ToSql compilation error in the joined select.

Common situations: Callers computing PerPage dynamically and passing 0 or negative values; code changes to the main query leaving mismatched placeholders; dialect-specific builder regressions.

Related errors


AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30). Data as JSON: /api/errors/1f58f49be6f0b965. Report an issue: GitHub.