mattermost-community/focalboard · error
error validating block %s: %w
Error message
error validating block %s: %w
What it means
This is a wrapped validation failure raised by insertBlock when the incoming model.Block fails block.IsValid(). It means the block (card, board item, text, etc.) violates Focalboard's structural rules (e.g. empty ID, invalid type, bad parent/child fields). The original validation error is preserved via %w so callers can inspect it with errors.As/Is against the model's ErrInvalidBlock error chain.
Source
Thrown at server/services/store/sqlstore/blocks.go:232
}
err = json.Unmarshal([]byte(fieldsJSON), &block.Fields)
if err != nil {
// handle this error
s.logger.Error(`ERROR blocksFromRows fields`, mlog.Err(err))
return nil, err
}
results = append(results, &block)
}
return results, nil
}
func (s *SQLStore) insertBlock(db sq.BaseRunner, block *model.Block, userID string) error {
if err := block.IsValid(); err != nil {
return fmt.Errorf("error validating block %s: %w", block.ID, err)
}
fieldsJSON, err := json.Marshal(block.Fields)
if err != nil {
return err
}
existingBlock, err := s.getBlock(db, block.ID)
if err != nil && !model.IsErrNotFound(err) {
return err
}
block.UpdateAt = utils.GetMillis()
block.ModifiedBy = userID
insertQuery := s.getQueryBuilder(db).Insert("").
Columns(
"channel_id",View on GitHub (pinned to a84bbb65e3)
Solutions
- Log/inspect the wrapped inner error (errors.Unwrap or %v of the returned error) to see exactly which field IsValid rejected
- Ensure block.ID is set to a valid generated ID (e.g. utils.NewID()) before inserting
- Ensure block.Type is one of the supported model.BlockType values and other required fields (BoardID, ParentID, Title) are populated
- If the data comes from an import, pre-validate every block with block.IsValid() before calling the store
Example fix
// before
block := &model.Block{Title: "hello"}
s.InsertBlock(block, userID)
// after
block := &model.Block{ID: utils.NewID(), Type: model.TypeCard, Title: "hello", BoardID: boardID, ParentID: parentID}
if err := block.IsValid(); err != nil {
return err
}
s.InsertBlock(block, userID) Defensive patterns
Strategy: validation
Validate before calling
func validForInsert(b *model.Block) error {
if b == nil || b.ID == "" {
return fmt.Errorf("block ID required")
}
return b.IsValid()
}
// call before: if err := validForInsert(block); err != nil { return err } Type guard
func isInsertableBlock(b *model.Block) bool {
return b != nil && b.ID != "" && b.IsValid() == nil
} Try / catch
if err := store.InsertBlock(block, userID); err != nil {
var verr error
if errors.As(err, &verr) && strings.Contains(err.Error(), "error validating block") {
return fmt.Errorf("block %s invalid: %w", block.ID, err)
}
return err
} Prevention
- Always assign a fresh ID (utils.NewID()) to programmatically created blocks
- Run block.IsValid() on imported/bulk data before calling the store
- Keep block.Type within the supported set defined in the model package
- Log the unwrapped inner error to pinpoint the rejected field
When it happens
Trigger: Calling InsertBlock or InsertBlocks (or the higher-level patchBlock/createBoardsAndBlocks flows) with a block whose ID is empty, whose Type is not a registered block type, whose boardID/parentID references are malformed, or otherwise failing model.Block.IsValid().
Common situations: Importing JSON block dumps with missing or empty 'id' fields; writing client code that constructs blocks with a Type typo; API automation sending blocks without required fields; restoring backups with legacy/corrupted block shapes.
Related errors
- no user ID
- No User IDs
- block fields size limit exceeded
- at least one board is required
- at least one block is required
AI-assisted analysis of mattermost-community/focalboard@a84bbb65e3 (2026-08-30).
Data as JSON: /api/errors/d0472f59cd3afa15.
Report an issue: GitHub.