apache/answer · error

update tag failed

Error message

update tag failed: %w

What it means

Wraps the xorm Update error when persisting a tag's recomputed question_count in the main branch of updateTagCount (tags that have available tag relations). The row UPDATE failed, the tag ID is logged, and the migration aborts.

Solutions

  1. Read the wrapped driver error to distinguish lock timeout from schema issues
  2. Verify the question_count column exists
  3. Re-run the migration; updates are idempotent
  4. Batch the updates or run during low-traffic windows to reduce lock contention

Example fix

// before
if _, err = x.Context(ctx).Update(tag, &entity.Tag{ID: tag.ID}); err != nil {
    return fmt.Errorf("update tag failed: %w", err)
}
// after
if _, err = x.Context(ctx).Cols("question_count").Update(tag, &entity.Tag{ID: tag.ID}); err != nil {
    return fmt.Errorf("update tag failed: %w", err)
}
Defensive patterns

Strategy: retry

Validate before calling

if has, _ := x.Context(ctx).IsColumnExist("tag", "question_count"); !has {
    return fmt.Errorf("tag.question_count column missing; apply DDL first")
}

Try / catch

if _, err = x.Context(ctx).Update(tag, &entity.Tag{ID: tag.ID}); err != nil {
    if isRetryable(err) { // e.g. lock wait timeout / connection reset
        time.Sleep(time.Second)
        _, err = x.Context(ctx).Update(tag, &entity.Tag{ID: tag.ID})
    }
    if err != nil { return fmt.Errorf("update tag failed: %w", err) }
}

Prevention

When it happens

Trigger: x.Context(ctx).Update(tag, &entity.Tag{ID: tag.ID}) failing mid-loop due to connection drop, missing question_count column, row lock contention, or cancelled context.

Common situations: Large tag tables updated one-by-one over unreliable connections; concurrent tag updates causing lock waits; running before the schema change added question_count.

Related errors


AI-assisted analysis of apache/answer@3b9f137061 (2026-09-05). Data as JSON: /api/errors/3ece562d4cd1b50d. Report an issue: GitHub.

Appendix: source

Thrown at internal/migrations/v13.go:245

		_, ok := tagCountMap[v.TagID]
		if !ok {
			tagCountMap[v.TagID] = 1
		} else {
			tagCountMap[v.TagID]++
		}
	}
	TagList := make([]entity.Tag, 0)
	err = x.Context(ctx).Find(&TagList, &entity.Tag{})
	if err != nil {
		return fmt.Errorf("get tag  failed: %w", err)
	}
	for _, tag := range TagList {
		_, ok := tagCountMap[tag.ID]
		if ok {
			tag.QuestionCount = tagCountMap[tag.ID]
			if _, err = x.Context(ctx).Update(tag, &entity.Tag{ID: tag.ID}); err != nil {
				log.Errorf("update %+v tag failed: %s", tag.ID, err)
				return fmt.Errorf("update tag failed: %w", err)
			}
		} else {
			tag.QuestionCount = 0
			if _, err = x.Context(ctx).Cols("question_count").Update(tag, &entity.Tag{ID: tag.ID}); err != nil {
				log.Errorf("update %+v tag failed: %s", tag.ID, err)
				return fmt.Errorf("update tag failed: %w", err)
			}
		}
	}
	return nil
}

// updateUserQuestionCount update user question count
func updateUserQuestionCount(ctx context.Context, x *xorm.Engine) error {
	questionList := make([]QuestionV13, 0)
	err := x.Context(ctx).Where(builder.Lt{"status": entity.QuestionStatusDeleted}).Find(&questionList, &QuestionV13{})
	if err != nil {
		return fmt.Errorf("get question  failed: %w", err)

View on GitHub (pinned to 3b9f137061)