Skip to content

Accessing the public link of a private poll as a logged in user corrupts Poll view #4192

@ronnybremer

Description

@ronnybremer

⚠️ This issue respects the following points: ⚠️

  • This is a bug, not a question or a configuration/webserver/proxy issue.
  • This issue is not already reported on Github (I've searched it).
  • I agree to follow Nextcloud's Code of Conduct.

What went wrong, what did you observe?

When clicking on a public link of a private poll in a browser window, where the poll owner is already logged in to NC, the poll gets duplicated in the list of polls and access to the details is no longer possible afterwards.

After that happened, accessing the poll page in NC produces the errors below. I analyzed the database and found redundant entries in the oc_polls_share table referring to the same poll_id and user_id with different tokens. After removing the newest redundant entries from that table (leaving only the first one in place), functionality resumes and the error messages in the log are no longer happening.

What did you expect, how polls should behave instead?

The poll to open so the owner can make their choices.

What steps does it need to replay this bug?

  1. create a private poll with some options
  2. create a public link
  3. copy the link URL
  4. paste the link URL into a new tab in the same browser (not in private-browsing mode)
  5. go back to the NC tab and refresh the poll list
  6. find the poll twice in there and clicking on any of them will lead to an empty page

Affected polls version

8.1.4

Installation method

Installed/updated from the appstore (Apps section of your site)

Installation type

Updated from previous major version (i.e. 7.x.x to 8.x.x)

Can you rule out that any extension you use is involved in the issue?

  • I have checked all browser extension

Which browser did you use, when experiencing the bug?

  • Firefox
  • Chrome
  • Chromium/Chromium based (i.e. Edge)
  • Safari
  • Other/Don't know

Other browser

No response

Add your browser log here

Additional client environment information

No response

NC version

Nextcloud 31

Other Nextcloud version

No response

PHP engine version

PHP 8.4

Other PHP version

No response

Database engine

PostgreSQL

Database Engine version or other Database

No response

Which user-backends are you using?

  • Default user-backend (database)
  • LDAP/ Active Directory
  • SSO - SAML
  • Other/Don't know

Add your nextcloud server log here

{"reqId":"aIeXfrLhCqYj8T7lwpyBLAAA0go","level":3,"time":"July 28, 2025 15:30:08","remoteAddr":"**redacted**","user":"testuser","app":"index","method":"GET","url":"/index.php/apps/polls/poll/79?time=1753716606907","message":"Did not expect more than one result when executing: query \"SELECT `polls_polls`.*, MAX(options.timestamp) AS max_date, coalesce(user_shares.type, '') AS user_role, `user_shares`.`locked` AS `is_current_user_locked`, coalesce(user_shares.token, '') AS share_token, string_agg(distinct group_shares.user_id::varchar, ',') AS group_shares, string_agg(distinct poll_groups.group_id::varchar, ',') AS poll_groups, string_agg(distinct poll_group_shares.type::varchar, ',') AS poll_group_user_shares, COUNT(DISTINCT(votes.id)) AS current_user_votes, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'yes' THEN votes.id END)) AS current_user_votes_yes, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'no' THEN votes.id END)) AS current_user_votes_no, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'maybe' THEN votes.id END)) AS current_user_votes_maybe, COUNT(DISTINCT(CASE WHEN vote_options_sub.id is NULL THEN votes.id END)) AS current_user_orphaned_votes, COUNT(DISTINCT(participants.user_id)) AS participants_count FROM `*PREFIX*polls_polls` `polls_polls` LEFT JOIN `*PREFIX*polls_options` `options` ON (`options`.`poll_id` = `polls_polls`.`id`) AND (`options`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_share` `user_shares` ON (`user_shares`.`poll_id` = `polls_polls`.`id`) AND (`user_shares`.`user_id` = :dcValue1) AND (`user_shares`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_share` `group_shares` ON (`group_shares`.`poll_id` = `polls_polls`.`id`) AND (`group_shares`.`type` = 'group') AND (`group_shares`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_groups_polls` `poll_groups` ON `polls_polls`.`id` = `poll_groups`.`poll_id` LEFT JOIN `*PREFIX*polls_votes` `votes` ON (`votes`.`poll_id` = `polls_polls`.`id`) AND (`votes`.`user_id` = :dcValue3) LEFT JOIN `*PREFIX*polls_votes` `participants` ON `participants`.`poll_id` = `polls_polls`.`id` LEFT JOIN `*PREFIX*polls_share` `poll_group_shares` ON (`poll_group_shares`.`group_id` = `poll_groups`.`group_id`) AND (`poll_group_shares`.`deleted` = '0') AND (`poll_group_shares`.`user_id` = :dcValue2) LEFT JOIN `*PREFIX*polls_options` `vote_options_sub` ON (`vote_options_sub`.`poll_id` = `votes`.`poll_id`) AND (`vote_options_sub`.`poll_option_text` = `votes`.`vote_option_text`) AND (`vote_options_sub`.`deleted` = '0') WHERE `polls_polls`.`id` = :dcValue4 GROUP BY `polls_polls`.`id`, `user_shares`.`type`, `user_shares`.`locked`, `user_shares`.`token`\"; ","userAgent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Safari/605.1.15","version":"31.0.7.1","exception":{"Exception":"OCP\\AppFramework\\Db\\MultipleObjectsReturnedException","Message":"Did not expect more than one result when executing: query \"SELECT `polls_polls`.*, MAX(options.timestamp) AS max_date, coalesce(user_shares.type, '') AS user_role, `user_shares`.`locked` AS `is_current_user_locked`, coalesce(user_shares.token, '') AS share_token, string_agg(distinct group_shares.user_id::varchar, ',') AS group_shares, string_agg(distinct poll_groups.group_id::varchar, ',') AS poll_groups, string_agg(distinct poll_group_shares.type::varchar, ',') AS poll_group_user_shares, COUNT(DISTINCT(votes.id)) AS current_user_votes, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'yes' THEN votes.id END)) AS current_user_votes_yes, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'no' THEN votes.id END)) AS current_user_votes_no, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'maybe' THEN votes.id END)) AS current_user_votes_maybe, COUNT(DISTINCT(CASE WHEN vote_options_sub.id is NULL THEN votes.id END)) AS current_user_orphaned_votes, COUNT(DISTINCT(participants.user_id)) AS participants_count FROM `*PREFIX*polls_polls` `polls_polls` LEFT JOIN `*PREFIX*polls_options` `options` ON (`options`.`poll_id` = `polls_polls`.`id`) AND (`options`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_share` `user_shares` ON (`user_shares`.`poll_id` = `polls_polls`.`id`) AND (`user_shares`.`user_id` = :dcValue1) AND (`user_shares`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_share` `group_shares` ON (`group_shares`.`poll_id` = `polls_polls`.`id`) AND (`group_shares`.`type` = 'group') AND (`group_shares`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_groups_polls` `poll_groups` ON `polls_polls`.`id` = `poll_groups`.`poll_id` LEFT JOIN `*PREFIX*polls_votes` `votes` ON (`votes`.`poll_id` = `polls_polls`.`id`) AND (`votes`.`user_id` = :dcValue3) LEFT JOIN `*PREFIX*polls_votes` `participants` ON `participants`.`poll_id` = `polls_polls`.`id` LEFT JOIN `*PREFIX*polls_share` `poll_group_shares` ON (`poll_group_shares`.`group_id` = `poll_groups`.`group_id`) AND (`poll_group_shares`.`deleted` = '0') AND (`poll_group_shares`.`user_id` = :dcValue2) LEFT JOIN `*PREFIX*polls_options` `vote_options_sub` ON (`vote_options_sub`.`poll_id` = `votes`.`poll_id`) AND (`vote_options_sub`.`poll_option_text` = `votes`.`vote_option_text`) AND (`vote_options_sub`.`deleted` = '0') WHERE `polls_polls`.`id` = :dcValue4 GROUP BY `polls_polls`.`id`, `user_shares`.`type`, `user_shares`.`locked`, `user_shares`.`token`\"; ","Code":0,"Trace":[{"file":"/var/www/html/nextcloud/lib/public/AppFramework/Db/QBMapper.php","line":375,"function":"findOneQuery","class":"OCP\\AppFramework\\Db\\QBMapper","type":"->"},{"file":"/var/www/html/nextcloud/apps/polls/lib/Db/PollMapper.php","line":73,"function":"findEntity","class":"OCP\\AppFramework\\Db\\QBMapper","type":"->"},{"file":"/var/www/html/nextcloud/apps/polls/lib/Service/PollService.php","line":176,"function":"find","class":"OCA\\Polls\\Db\\PollMapper","type":"->"},{"file":"/var/www/html/nextcloud/apps/polls/lib/Controller/PollController.php","line":111,"function":"get","class":"OCA\\Polls\\Service\\PollService","type":"->"},{"file":"/var/www/html/nextcloud/apps/polls/lib/Controller/PollController.php","line":105,"function":"getFullPoll","class":"OCA\\Polls\\Controller\\PollController","type":"->"},{"file":"/var/www/html/nextcloud/apps/polls/lib/Controller/BaseController.php","line":42,"function":"OCA\\Polls\\Controller\\{closure}","class":"OCA\\Polls\\Controller\\PollController","type":"->","args":["*** sensitive parameters replaced ***"]},{"file":"/var/www/html/nextcloud/apps/polls/lib/Controller/PollController.php","line":105,"function":"response","class":"OCA\\Polls\\Controller\\BaseController","type":"->"},{"file":"/var/www/html/nextcloud/lib/private/AppFramework/Http/Dispatcher.php","line":200,"function":"getFull","class":"OCA\\Polls\\Controller\\PollController","type":"->"},{"file":"/var/www/html/nextcloud/lib/private/AppFramework/Http/Dispatcher.php","line":114,"function":"executeController","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"/var/www/html/nextcloud/lib/private/AppFramework/App.php","line":161,"function":"dispatch","class":"OC\\AppFramework\\Http\\Dispatcher","type":"->"},{"file":"/var/www/html/nextcloud/lib/private/Route/Router.php","line":315,"function":"main","class":"OC\\AppFramework\\App","type":"::"},{"file":"/var/www/html/nextcloud/lib/base.php","line":1040,"function":"match","class":"OC\\Route\\Router","type":"->"},{"file":"/var/www/html/nextcloud/index.php","line":24,"function":"handleRequest","class":"OC","type":"::"}],"File":"/var/www/html/nextcloud/lib/public/AppFramework/Db/QBMapper.php","Line":286,"message":"Did not expect more than one result when executing: query \"SELECT `polls_polls`.*, MAX(options.timestamp) AS max_date, coalesce(user_shares.type, '') AS user_role, `user_shares`.`locked` AS `is_current_user_locked`, coalesce(user_shares.token, '') AS share_token, string_agg(distinct group_shares.user_id::varchar, ',') AS group_shares, string_agg(distinct poll_groups.group_id::varchar, ',') AS poll_groups, string_agg(distinct poll_group_shares.type::varchar, ',') AS poll_group_user_shares, COUNT(DISTINCT(votes.id)) AS current_user_votes, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'yes' THEN votes.id END)) AS current_user_votes_yes, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'no' THEN votes.id END)) AS current_user_votes_no, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'maybe' THEN votes.id END)) AS current_user_votes_maybe, COUNT(DISTINCT(CASE WHEN vote_options_sub.id is NULL THEN votes.id END)) AS current_user_orphaned_votes, COUNT(DISTINCT(participants.user_id)) AS participants_count FROM `*PREFIX*polls_polls` `polls_polls` LEFT JOIN `*PREFIX*polls_options` `options` ON (`options`.`poll_id` = `polls_polls`.`id`) AND (`options`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_share` `user_shares` ON (`user_shares`.`poll_id` = `polls_polls`.`id`) AND (`user_shares`.`user_id` = :dcValue1) AND (`user_shares`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_share` `group_shares` ON (`group_shares`.`poll_id` = `polls_polls`.`id`) AND (`group_shares`.`type` = 'group') AND (`group_shares`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_groups_polls` `poll_groups` ON `polls_polls`.`id` = `poll_groups`.`poll_id` LEFT JOIN `*PREFIX*polls_votes` `votes` ON (`votes`.`poll_id` = `polls_polls`.`id`) AND (`votes`.`user_id` = :dcValue3) LEFT JOIN `*PREFIX*polls_votes` `participants` ON `participants`.`poll_id` = `polls_polls`.`id` LEFT JOIN `*PREFIX*polls_share` `poll_group_shares` ON (`poll_group_shares`.`group_id` = `poll_groups`.`group_id`) AND (`poll_group_shares`.`deleted` = '0') AND (`poll_group_shares`.`user_id` = :dcValue2) LEFT JOIN `*PREFIX*polls_options` `vote_options_sub` ON (`vote_options_sub`.`poll_id` = `votes`.`poll_id`) AND (`vote_options_sub`.`poll_option_text` = `votes`.`vote_option_text`) AND (`vote_options_sub`.`deleted` = '0') WHERE `polls_polls`.`id` = :dcValue4 GROUP BY `polls_polls`.`id`, `user_shares`.`type`, `user_shares`.`locked`, `user_shares`.`token`\"; ","exception":{},"CustomMessage":"Did not expect more than one result when executing: query \"SELECT `polls_polls`.*, MAX(options.timestamp) AS max_date, coalesce(user_shares.type, '') AS user_role, `user_shares`.`locked` AS `is_current_user_locked`, coalesce(user_shares.token, '') AS share_token, string_agg(distinct group_shares.user_id::varchar, ',') AS group_shares, string_agg(distinct poll_groups.group_id::varchar, ',') AS poll_groups, string_agg(distinct poll_group_shares.type::varchar, ',') AS poll_group_user_shares, COUNT(DISTINCT(votes.id)) AS current_user_votes, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'yes' THEN votes.id END)) AS current_user_votes_yes, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'no' THEN votes.id END)) AS current_user_votes_no, COUNT(DISTINCT(CASE WHEN votes.vote_answer = 'maybe' THEN votes.id END)) AS current_user_votes_maybe, COUNT(DISTINCT(CASE WHEN vote_options_sub.id is NULL THEN votes.id END)) AS current_user_orphaned_votes, COUNT(DISTINCT(participants.user_id)) AS participants_count FROM `*PREFIX*polls_polls` `polls_polls` LEFT JOIN `*PREFIX*polls_options` `options` ON (`options`.`poll_id` = `polls_polls`.`id`) AND (`options`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_share` `user_shares` ON (`user_shares`.`poll_id` = `polls_polls`.`id`) AND (`user_shares`.`user_id` = :dcValue1) AND (`user_shares`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_share` `group_shares` ON (`group_shares`.`poll_id` = `polls_polls`.`id`) AND (`group_shares`.`type` = 'group') AND (`group_shares`.`deleted` = '0') LEFT JOIN `*PREFIX*polls_groups_polls` `poll_groups` ON `polls_polls`.`id` = `poll_groups`.`poll_id` LEFT JOIN `*PREFIX*polls_votes` `votes` ON (`votes`.`poll_id` = `polls_polls`.`id`) AND (`votes`.`user_id` = :dcValue3) LEFT JOIN `*PREFIX*polls_votes` `participants` ON `participants`.`poll_id` = `polls_polls`.`id` LEFT JOIN `*PREFIX*polls_share` `poll_group_shares` ON (`poll_group_shares`.`group_id` = `poll_groups`.`group_id`) AND (`poll_group_shares`.`deleted` = '0') AND (`poll_group_shares`.`user_id` = :dcValue2) LEFT JOIN `*PREFIX*polls_options` `vote_options_sub` ON (`vote_options_sub`.`poll_id` = `votes`.`poll_id`) AND (`vote_options_sub`.`poll_option_text` = `votes`.`vote_option_text`) AND (`vote_options_sub`.`deleted` = '0') WHERE `polls_polls`.`id` = :dcValue4 GROUP BY `polls_polls`.`id`, `user_shares`.`type`, `user_shares`.`locked`, `user_shares`.`token`\"; "}}

Additional environment informations

No response

Configuration report

List of activated Apps

Nextcloud Signing status

Additional Information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions