scenic-views/scenic · error · ArgumentError
Cannot replace materialized views
Error message
Cannot replace materialized views
What it means
Postgres implements CREATE OR REPLACE VIEW for plain views only; there is no CREATE OR REPLACE MATERIALIZED VIEW statement. Because replace_view compiles to exactly that SQL, Scenic raises ArgumentError ('Cannot replace materialized views') whenever materialized is truthy, regardless of server version, rather than emitting SQL the server would reject anyway.
Source
Thrown at lib/scenic/statements.rb:168
#
# Does not work with materialized views due to lack of database support.
#
# @param name [String, Symbol] The name of the database view.
# @param version [Fixnum] The version number of the view.
# @param revert_to_version [Fixnum] The version number to rollback to on
# `rake db rollback`
# @return The database response from executing the create statement.
#
# @example
# replace_view :engagement_reports, version: 3, revert_to_version: 2
#
def replace_view(name, version: nil, revert_to_version: nil, materialized: false)
if version.blank?
raise ArgumentError, "version is required"
end
if materialized
raise ArgumentError, "Cannot replace materialized views"
end
sql_definition = definition(name, version)
Scenic.database.replace_view(name, sql_definition)
end
private
def definition(name, version)
Scenic::Definition.new(name, version).to_sql
end
def materialized_options(materialized)
if materialized.is_a? Hash
{
no_data: materialized.fetch(:no_data, false),
side_by_side: materialized.fetch(:side_by_side, false)View on GitHub (pinned to f2162dbddb)
Solutions
- Use the supported path: update_view :reports, version: 2, revert_to_version: 1, materialized: true (drop and recreate, with existing view indexes automatically reapplied)
- If lock duration is the concern, update_view :reports, version: 2, materialized: { side_by_side: true } inside a transactional migration swaps atomically with minimal lock time
- If replace_view was chosen to untangle view dependencies, order the migrations so dependents update first instead
Example fix
# before (ArgumentError: Cannot replace materialized views) replace_view :reports, version: 2, materialized: true # after: supported materialized update path update_view :reports, version: 2, revert_to_version: 1, materialized: true
Defensive patterns
Strategy: validation
Validate before calling
view = Scenic.database.views.find { |v| v.name.to_s == 'reports' }
if view&.materialized
update_view :reports, version: 2, materialized: true
else
replace_view :reports, version: 2
end Type guard
def materialized_view?(name)
Scenic.database.views.find { |v| v.name.to_s == name.to_s }&.materialized == true
end Prevention
- Internalize the split: replace_view is plain-view-only; materialized views always update via update_view ... materialized: true
- When converting a plain view to a materialized one, switch the migration method too
- Flag materialized: true combined with replace_view as a bug in migration review
When it happens
Trigger: replace_view :reports, version: 2, materialized: true; replace_view :reports, version: 2, materialized: { side_by_side: true } (any truthy value, including a Hash, hits the guard); copy-pasting a plain-view replace_view migration and turning the flag on.
Common situations: A team reaches for replace_view on a materialized view to dodge dependency-ordering pain between tangled views; converting a plain view into a materialized one without switching the migration method; templates shared across view kinds.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Materialized views require Postgres 9.3 or newer
- Concurrent materialized view refreshes require Postgres 9.4
- a transaction is required to perform a side-by-side update
- version is required
- #{method} is reversible only if given a revert_to_version
AI-assisted analysis of scenic-views/scenic@f2162dbddb (2026-08-23).
Data as JSON: /api/errors/dc551ae490152fcf.
Report an issue: GitHub.