"discourse_solved_solved_topics" verletzt NOT NULL-Einschränkung während des Rebuilds

Hello everyone!

During a rebuild on a forum in the stable branch, I have an error related to the solved plugin.

Here are the logs:

2025-12-20 03:48:21.715 UTC [1122] discourse@discourse ERROR:  null value in column "answer_post_id" of relation "discourse_solved_solved_topics" violates not-null constraint
2025-12-20 03:48:21.715 UTC [1122] discourse@discourse DETAIL:  Failing row contains (3735, 35506, null, -1, null, 2021-05-12 18:38:58.11516, 2021-05-12 18:38:58.11516).
2025-12-20 03:48:21.715 UTC [1122] discourse@discourse STATEMENT:  INSERT INTO discourse_solved_solved_topics (
	  topic_id,
	  answer_post_id,
	  topic_timer_id,
	  accepter_user_id,
	  created_at,
	  updated_at
	)
	SELECT
	  tc.topic_id,
	  tc.answer_post_id,
	  tc.topic_timer_id,
	  tc.accepter_user_id,
	  tc.created_at,
	  tc.updated_at
	FROM (
	  SELECT
	    tc.topic_id,
	    CAST(tc.value AS INTEGER) AS answer_post_id,
	    CAST(tc2.value AS INTEGER) AS topic_timer_id,
	    COALESCE(ua.acting_user_id, -1) AS accepter_user_id,
	    tc.created_at,
	    tc.updated_at,
	    ROW_NUMBER() OVER (PARTITION BY tc.topic_id ORDER BY tc.created_at ASC) AS rn_topic,
	    ROW_NUMBER() OVER (PARTITION BY CAST(tc.value AS INTEGER) ORDER BY tc.created_at ASC) AS rn_answer
	  FROM topic_custom_fields tc
	  LEFT JOIN topic_custom_fields tc2 ON tc2.topic_id = tc.topic_id AND tc2.name = 'solved_auto_close_topic_timer_id'
	  LEFT JOIN user_actions ua ON ua.target_topic_id = tc.topic_id AND ua.action_type = 15
	  WHERE tc.name = 'accepted_answer_post_id'
	    AND tc.id > 0
	    AND tc.id <= 0 + 10000
	) tc
	WHERE tc.rn_topic = 1 AND tc.rn_answer = 1
	ON CONFLICT DO NOTHING
	
rake aborted!
StandardError: An error has occurred, all later migrations canceled: (StandardError)

ERROR:  null value in column "answer_post_id" of relation "discourse_solved_solved_topics" violates not-null constraint
DETAIL:  Failing row contains (3735, 35506, null, -1, null, 2021-05-12 18:38:58.11516, 2021-05-12 18:38:58.11516).
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/pg/alias_method.rb:109:in `exec'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/pg/alias_method.rb:109:in `async_exec'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/postgres/connection.rb:217:in `run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/active_record_postgres/connection.rb:38:in `block in run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/active_record_postgres/connection.rb:34:in `block in with_lock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-8.0.2.1/lib/active_support/concurrency/null_lock.rb:9:in `synchronize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/active_record_postgres/connection.rb:34:in `with_lock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/active_record_postgres/connection.rb:38:in `run'
/var/www/discourse/lib/mini_sql_multisite_connection.rb:109:in `run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/postgres/connection.rb:196:in `exec'
/var/www/discourse/plugins/discourse-solved/db/migrate/20250318024953_copy_solved_topic_custom_field_to_discourse_solved_solved_topics.rb:17:in `up'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:994:in `public_send'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:994:in `exec_migration'
/var/www/discourse/lib/freedom_patches/schema_migration_details.rb:8:in `block in exec_migration'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/benchmark-0.4.1/lib/benchmark.rb:305:in `measure'
/var/www/discourse/lib/freedom_patches/schema_migration_details.rb:8:in `exec_migration'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:975:in `block (2 levels) in migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-8.0.2.1/lib/active_support/benchmark.rb:17:in `realtime'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:974:in `block in migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:412:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:973:in `migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1187:in `migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1535:in `block in execute_migration_in_transaction'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1588:in `ddl_transaction'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1534:in `execute_migration_in_transaction'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1509:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1509:in `migrate_without_lock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1454:in `block in migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1606:in `with_advisory_lock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1454:in `migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1261:in `up'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1236:in `migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/tasks/database_tasks.rb:270:in `migrate'
/var/www/discourse/lib/tasks/db.rake:267:in `block (2 levels) in <main>'
/var/www/discourse/lib/distributed_mutex.rb:53:in `block in synchronize'
/var/www/discourse/lib/distributed_mutex.rb:49:in `synchronize'
/var/www/discourse/lib/distributed_mutex.rb:49:in `synchronize'
/var/www/discourse/lib/distributed_mutex.rb:34:in `synchronize'
/var/www/discourse/lib/tasks/db.rake:242:in `block in <main>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.3.0/exe/rake:27:in `<top (required)>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'

Caused by:
PG::NotNullViolation: ERROR:  null value in column "answer_post_id" of relation "discourse_solved_solved_topics" violates not-null constraint (PG::NotNullViolation)
DETAIL:  Failing row contains (3735, 35506, null, -1, null, 2021-05-12 18:38:58.11516, 2021-05-12 18:38:58.11516).
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/pg/alias_method.rb:109:in `exec'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/pg/alias_method.rb:109:in `async_exec'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/postgres/connection.rb:217:in `run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/active_record_postgres/connection.rb:38:in `block in run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/active_record_postgres/connection.rb:34:in `block in with_lock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-8.0.2.1/lib/active_support/concurrency/null_lock.rb:9:in `synchronize'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/active_record_postgres/connection.rb:34:in `with_lock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/active_record_postgres/connection.rb:38:in `run'
/var/www/discourse/lib/mini_sql_multisite_connection.rb:109:in `run'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/mini_sql-1.6.0/lib/mini_sql/postgres/connection.rb:196:in `exec'
/var/www/discourse/plugins/discourse-solved/db/migrate/20250318024953_copy_solved_topic_custom_field_to_discourse_solved_solved_topics.rb:17:in `up'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:994:in `public_send'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:994:in `exec_migration'
/var/www/discourse/lib/freedom_patches/schema_migration_details.rb:8:in `block in exec_migration'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/benchmark-0.4.1/lib/benchmark.rb:305:in `measure'
/var/www/discourse/lib/freedom_patches/schema_migration_details.rb:8:in `exec_migration'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:975:in `block (2 levels) in migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activesupport-8.0.2.1/lib/active_support/benchmark.rb:17:in `realtime'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:974:in `block in migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:412:in `with_connection'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:973:in `migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1187:in `migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1535:in `block in execute_migration_in_transaction'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1588:in `ddl_transaction'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1534:in `execute_migration_in_transaction'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1509:in `each'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1509:in `migrate_without_lock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1454:in `block in migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1606:in `with_advisory_lock'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1454:in `migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1261:in `up'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/migration.rb:1236:in `migrate'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/activerecord-8.0.2.1/lib/active_record/tasks/database_tasks.rb:270:in `migrate'
/var/www/discourse/lib/tasks/db.rake:267:in `block (2 levels) in <main>'
/var/www/discourse/lib/distributed_mutex.rb:53:in `block in synchronize'
/var/www/discourse/lib/distributed_mutex.rb:49:in `synchronize'
/var/www/discourse/lib/distributed_mutex.rb:49:in `synchronize'
/var/www/discourse/lib/distributed_mutex.rb:34:in `synchronize'
/var/www/discourse/lib/tasks/db.rake:242:in `block in <main>'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rake-13.3.0/exe/rake:27:in `<top (required)>'
/usr/local/bin/bundle:25:in `load'
/usr/local/bin/bundle:25:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
I, [2025-12-20T03:48:21.794538 #1]  INFO -- : gem install geocoder -v 1.8.3 -i /var/www/discourse/plugins/discourse-locations/gems/3.3.8 --no-document --ignore-dependencies --no-user-install
Successfully installed geocoder-1.8.3
1 gem installed
== 20250318024953 CopySolvedTopicCustomFieldToDiscourseSolvedSolvedTopics: migrating 

I, [2025-12-20T03:48:21.795736 #1]  INFO -- : Terminating async processes
I, [2025-12-20T03:48:21.795838 #1]  INFO -- : Sending INT to HOME=/var/lib/postgresql USER=postgres exec chpst -u postgres:postgres:ssl-cert -U postgres:postgres:ssl-cert /usr/lib/postgresql/15/bin/postmaster -D /etc/postgresql/15/main pid: 45
I, [2025-12-20T03:48:21.795934 #1]  INFO -- : Sending TERM to exec chpst -u redis -U redis /usr/bin/redis-server /etc/redis/redis.conf pid: 112
112:signal-handler (1766202501) Received SIGTERM scheduling shutdown...
2025-12-20 03:48:21.796 UTC [45] LOG:  received fast shutdown request
2025-12-20 03:48:21.800 UTC [45] LOG:  aborting any active transactions
2025-12-20 03:48:21.808 UTC [45] LOG:  background worker "logical replication launcher" (PID 59) exited with exit code 1
2025-12-20 03:48:21.809 UTC [54] LOG:  shutting down
2025-12-20 03:48:21.811 UTC [54] LOG:  checkpoint starting: shutdown immediate
2025-12-20 03:48:21.861 UTC [54] LOG:  checkpoint complete: wrote 18 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.039 s, sync=0.006 s, total=0.052 s; sync files=10, longest=0.003 s, average=0.001 s; distance=161 kB, estimate=161 kB
112:M 20 Dec 2025 03:48:21.892 # User requested shutdown...
112:M 20 Dec 2025 03:48:21.892 * Saving the final RDB snapshot before exiting.
2025-12-20 03:48:21.918 UTC [45] LOG:  database system is shut down
112:M 20 Dec 2025 03:48:22.621 * DB saved on disk
112:M 20 Dec 2025 03:48:22.621 # Redis is now ready to exit, bye bye...


FAILED
--------------------
Pups::ExecError: cd /var/www/discourse && su discourse -c 'bundle exec rake db:migrate' failed with return #<Process::Status: pid 1016 exit 1>
Location of failure: /usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups/exec_command.rb:131:in `spawn'
exec failed with the params {"cd"=>"$home", "tag"=>"migrate", "hook"=>"db_migrate", "cmd"=>["su discourse -c 'bundle exec rake db:migrate'"]}
bootstrap failed with exit code 1
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.
./discourse-doctor may help diagnose the problem.

I managed to rebuild by deleting the solved plugin in the app.yml (using the - rm -rf discourse-solved command), and the owner of the forum could probably do without this plugin but I’d still like to fix this.

I don’t think the issue comes from the plugin, it may be a bad manipulation on the forum. But when I explore the database, I have at least 20-30 \N entries in value

Here is an extract:

id topic_id name value created at updated at
1579 35497 accepted_answer_post_id 301435 2021-05-10 20:18:57.780444 2021-05-10 20:18:57.780444
1583 35506 accepted_answer_post_id \N 2021-05-12 18:38:58.11516 2021-05-12 18:38:58.11516
423 21211 accepted_answer_post_id 153039 2019-09-04 21:01:37.811417 2019-09-04 21:01:37.811417
424 21685 accepted_answer_post_id 156850 2019-09-09 04:39:28.388591 2019-09-09 04:39:28.388591
425 21711 accepted_answer_post_id 157323 2019-09-11 11:51:14.375185 2019-09-11 11:51:14.375185
428 20982 accepted_answer_post_id 157807 2019-09-14 08:53:16.079032 2019-09-14 08:53:16.079032
429 4949 accepted_answer_post_id 157515 2019-09-16 07:57:00.862694 2019-09-16 07:57:00.862694
430 15439 accepted_answer_post_id 158645 2019-09-19 00:56:20.112603 2019-09-19 00:56:20.112603
1603 35710 accepted_answer_post_id \N 2021-05-19 20:58:06.598697 2021-05-19 20:58:06.598697
701 25377 accepted_answer_post_id 195459 2020-03-26 20:42:14.168898 2020-03-26 20:42:14.168898
434 21868 accepted_answer_post_id 159024 2019-09-22 10:09:09.671605 2019-09-22 10:09:09.671605

I need to tell you that I suck at sql queries, especially via command lines. I don’t really trust myself to delete these lines via terminal.

But anyway, what route do you recommand for me to fix this? A query (what type of querie?) ? A script, or something can be done in the forum directly?

Außer, dass es in den Kern verschoben wurde.
Diejenigen, bei denen die post_id Newline ist, sind das Problem. Sie sollten diese Datensätze einfach aus der Datenbank löschen (es ist möglicherweise über Rails möglich). Sie können wahrscheinlich Ask.discourse.com bitten, Ihnen zu sagen, wie.

Als möglicher Versuch… Ich glaube, das Löschen eines Themas entfernt automatisch die Lösung und löscht den Eintrag in discourse_solved_solved_topics. Ich bin mir nicht zu 100 % sicher, ob dies ohne das installierte „solved“-Plugin funktionieren könnte, aber es könnte sich lohnen, dies zu überprüfen?

Wenn Sie eine Abfrage im Data Explorer ausführen, um sie alle zu erfassen, eine löschen und die Abfrage erneut ausführen, um zu sehen, ob sie verschwunden ist, könnte dies ein einfacher Weg sein, um zu sehen, ob es funktionieren könnte?

Das Wiederherstellen des Themas stellt den Eintrag in discourse_solved_solved_topics nicht wieder her, daher könnte (potenziell :slight_smile:) ein schnelles „Löschen und Wiederherstellen“ sie ausräumen. :crossed_fingers:

Ich bin mir ziemlich sicher, dass es nicht funktionieren wird, da der Code, der das tut, im Plugin enthalten ist.

Ich bin mir auch ziemlich sicher, dass die Datenbank fehlerhaft ist. Es ist nicht vorgesehen, dass diese Spalte value Zeilenumbrüche enthält. Diese müssen aus der Datenbank gelöscht werden. Wenn Sie das nicht tun, werden Sie vergessen, wenn Sie versuchen, auf einen neuen Server zu wechseln und diese Datenbank wiederherzustellen (und dann wird es als „gelöst“ markiert sein, da es im Kern enthalten ist), und Sie müssen das alles noch einmal herausfinden.

1 „Gefällt mir“

Ah, ich dachte, das wäre ein langer Schuss. Ich war mir nicht sicher, wo die Bereinigung aufbewahrt wurde. :slight_smile:

Es sieht so aus, als hätte Alexander ein ähnliches Problem gehabt und den Weg über die Datenbank gewählt: Error upgrading to latest Discourse -- solved - #4 by Alexander_Wright

1 „Gefällt mir“