{"record":{"id":"6dd9297fe85e24a4","repo":"gastownhall/beads","slug":"apply-their-values-for-s-s-w","errorCode":null,"errorMessage":"apply their values for %s %s: %w","messagePattern":"apply their values for (.+?) (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/storage/versioncontrolops/conflicts.go","lineNumber":409,"sourceCode":"\t\t}\n\t\tsets := make([]string, len(names))\n\t\targs := make([]any, 0, len(names)+1)\n\t\tfor i, n := range names {\n\t\t\t// Column names are interpolated (MySQL cannot bind an\n\t\t\t// identifier) and come from the conflict table's own schema,\n\t\t\t// which a peer's schema merge can extend — gate them exactly\n\t\t\t// like the table name rather than trusting the source.\n\t\t\tif err := ValidateConflictTable(n); err != nil {\n\t\t\t\treturn fmt.Errorf(\"refusing to write unexpected column %q of %s: %w\", n, table, err)\n\t\t\t}\n\t\t\tsets[i] = fmt.Sprintf(\"`%s` = ?\", n)\n\t\t\targs = append(args, vals[i])\n\t\t}\n\t\targs = append(args, ourKey)\n\t\tstmt := fmt.Sprintf(\"UPDATE `%s` SET %s WHERE `%s` = ?\", table, strings.Join(sets, \", \"), keyCol) //nolint:gosec // identifiers validated above\n\t\tres, err := db.ExecContext(ctx, stmt, args...)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"apply their values for %s %s: %w\", table, key, err)\n\t\t}\n\t\t// Zero rows would mean the row we read the conflict for is no longer\n\t\t// there — another session on the same branch deleted it between the\n\t\t// read and the write. Clearing the conflict now would discard their\n\t\t// side under a --theirs invocation, undetectably. But zero is not\n\t\t// proof of that on its own (see conflictTargetStillPresent), so ask\n\t\t// before refusing: an operator who named this row deserves the abort\n\t\t// only when the row really is gone.\n\t\tif n, err := res.RowsAffected(); err != nil || n == 0 {\n\t\t\tpresent, err := conflictTargetStillPresent(ctx, db, table, keyCol, ourKey)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"confirm %s %s still exists after writing their values: %w\", table, key, err)\n\t\t\t}\n\t\t\tif !present {\n\t\t\t\treturn fmt.Errorf(\"their values for %s %s matched no row (was it deleted concurrently?); conflict left unresolved\", table, key)\n\t\t\t}\n\t\t}\n\t}","sourceCodeStart":391,"sourceCodeEnd":427,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/storage/versioncontrolops/conflicts.go#L391-L427","documentation":"The UPDATE that writes the peer's (their) values into the base table failed at the driver/database level. This wraps the raw ExecContext error; the conflict is intentionally left unresolved so the operator can diagnose rather than half-apply a resolution. Causes range from constraint violations to connection loss.","triggerScenarios":"ResolveConflictRows -> resolveOneConflictRow (theirs) executes `UPDATE <table> SET their values WHERE <keyCol> = ?`; the server rejects it (constraint violation, type mismatch after schema merge, lock timeout) or the connection fails.","commonSituations":"Their values violate a NOT NULL/UNIQUE/FK constraint that only the peer's schema enforced; schema merge changed a column type so their value no longer fits; row locked by another transaction; server restarted mid-resolution.","solutions":["Read the wrapped cause to see the exact SQL error (constraint, type, lock)","Reconcile the schema/type difference between branches, then resolve again","Run resolution inside a single transaction/session to avoid lock conflicts with concurrent writers","If a constraint blocks it, resolve that row by hand or relax/fix the constraint before applying theirs"],"exampleFix":"// before\nresolveOne(ctx, db, \"issues\", \"id\", \"42\", \"theirs\") // UPDATE fails: FK violation\n// after\n// fix referencing rows or use ON DELETE/UPDATE CASCADE, then:\nresolveOne(ctx, db, \"issues\", \"id\", \"42\", \"theirs\")","handlingStrategy":"try-catch","validationCode":"// pre-check constraints that their values must satisfy\n// e.g. verify no NULLs/unique clashes will be introduced by theirs\nrow, err := loadConflictRow(ctx, db, table, keyCol, key)\nif err != nil { return err }\nif err := checkConstraints(ctx, db, table, row, \"theirs\"); err != nil { return err }","typeGuard":null,"tryCatchPattern":"err := resolveOne(ctx, db, table, keyCol, key, \"theirs\")\nif err != nil && strings.Contains(err.Error(), \"apply their values for\") {\n    // conflict left unresolved; inspect cause and fix schema/constraints\n    log.Printf(\"row-level theirs blocked: %v\", err)\n    return resolveWithOperatorReview(ctx, db, table, keyCol, key)\n}\nreturn err","preventionTips":["Run resolution inside a single transaction to avoid lock contention","Align column types/constraints across branches before merging","Avoid concurrent writers during conflict resolution","Review wrapped SQL errors for constraint or type mismatches before retrying"],"tags":["database","dolt","update-failed","constraint-violation"],"backgroundTag":"update-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}