{"record":{"id":"5d737be1d45b8dd2","repo":"basecamp/fizzy","slug":"not-found","errorCode":null,"errorMessage":"Not Found","messagePattern":"Not Found","errorType":"http","errorClass":"ActionController::RoutingError","httpStatus":404,"severity":"error","filePath":"app/controllers/public/base_controller.rb","lineNumber":23,"sourceCode":"  before_action :ensure_board_accessible\n\n  layout \"public\"\n\n  private\n    def set_board\n      @board = Board.find_by_published_key(params[:board_id] || params[:id])\n    end\n\n    def set_card\n      @card = @board.cards.published.find_by!(number: params[:id]) if params[:board_id] && params[:id]\n    end\n\n    def set_public_cache_expiration\n      expires_in 30.seconds, public: true\n    end\n\n    def ensure_board_accessible\n      raise ActionController::RoutingError, \"Not Found\" if @board&.account&.cancelled?\n    end\nend\n","sourceCodeStart":5,"sourceCodeEnd":26,"githubUrl":"https://github.com/basecamp/fizzy/blob/7aabe7458060d8a1759a53b7ede39e74e6c0b20d/app/controllers/public/base_controller.rb#L5-L26","documentation":"Public board pages run through Public::BaseController, which resolves the board via Board.find_by_published_key and then calls ensure_board_accessible. That guard raises ActionController::RoutingError (\"Not Found\") whenever the board's owning account is cancelled, so Rails renders an HTTP 404. This is a deliberate gate that hides published boards of cancelled accounts instead of leaking that they exist.","triggerScenarios":"GET /public/boards/:publication_key, /public/boards/:publication_key/cards/:number, or the column/stream/closed/not_now sub-pages (all under the /{account_id} URL prefix on this multi-tenant app) where board.account.cancelled? is true. Every controller inheriting Public::BaseController (boards, cards, columns, streams, closeds, not_nows) hits this before_action after set_board.","commonSituations":"A shared public board link that worked yesterday starts returning 404 after the account's subscription lapsed or the account was closed. Stakeholders report the link as broken. Also: the 30-second public cache (expires_in 30.seconds, public: true) can serve a stale page briefly after cancellation, confusing debugging.","solutions":["Check the account state in console/admin (account.reload.cancelled?) and reactivate the subscription if the board should stay publicly visible.","Confirm the link uses the current publication key (board.publication.key) — republishing a board rotates it, and old keys return 404.","If you own the app, add rescue_from ActionController::RoutingError in Public::BaseController to render a branded 404 page instead of the default.","When cancelling an account, purge/expiry-tag the public board caches so stale rendered pages disappear immediately."],"exampleFix":"// before\nlink_to \"Public board\", published_board_url(board)\n\n// after (don't advertise links that will 404)\nlink_to \"Public board\", published_board_url(board) if board.publication.present? && !board.account.cancelled?","handlingStrategy":"validation","validationCode":"# before rendering or sharing a public board link\nboard = Board.find_by_published_key(key)\nreturn head :not_found if board.nil? || board.account&.cancelled?","typeGuard":"def public_board_available?(board)\n  board.present? && board.publication.present? && board.account.present? && !board.account.cancelled?\nend","tryCatchPattern":"# only if you need a branded page instead of Rails' default 404\nclass Public::BaseController < ApplicationController\n  rescue_from ActionController::RoutingError, with: :render_public_404\n\n  private\n    def render_public_404\n      render 'public/errors/not_found', status: :not_found\n    end\nend","preventionTips":["Surface account cancellation state in admin UIs so support knows why public links die.","When an account transitions to cancelled, purge the 30-second public board caches immediately.","Regenerate and redistribute publication links after republishing — keys rotate."],"tags":["rails","http-404","public-boards","subscription","routing-error"],"backgroundTag":"http-404-not-found","analyzedSha":"7aabe7458060d8a1759a53b7ede39e74e6c0b20d","analyzedAt":"2026-08-21T18:33:25.349Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}