{"record":{"id":"6ae2b573d80a2592","repo":"prestodb/presto","slug":"invalid-table-property-6ae2b5","errorCode":"INVALID_TABLE_PROPERTY","errorMessage":"%s must be positive, got %d","messagePattern":"(.+?) must be positive, got (.+?)","errorType":"error_code","errorClass":"PrestoException","httpStatus":null,"severity":"error","filePath":"presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergMaterializedViewProperties.java","lineNumber":135,"sourceCode":"                            null,\n                            false),\n                    PRESTO_MATERIALIZED_VIEW_USE_TIMESTAMP_BASED_STALENESS),\n            updatable(\n                    new PropertyMetadata<>(\n                            MAX_SNAPSHOTS_PER_REFRESH,\n                            \"Maximum number of snapshots consumed per base table per refresh. \" +\n                                    \"Unset falls back to the session default.\",\n                            INTEGER,\n                            Integer.class,\n                            null,\n                            false,\n                            value -> {\n                                if (value == null) {\n                                    return null;\n                                }\n                                int parsed = ((Number) value).intValue();\n                                if (parsed <= 0) {\n                                    throw new PrestoException(INVALID_TABLE_PROPERTY,\n                                            format(\"%s must be positive, got %d\", MAX_SNAPSHOTS_PER_REFRESH, parsed));\n                                }\n                                return parsed;\n                            },\n                            object -> object),\n                    PRESTO_MATERIALIZED_VIEW_MAX_SNAPSHOTS_PER_REFRESH,\n                    value -> Integer.toString((Integer) value)));\n\n    private static final Map<String, MaterializedViewProperty> MV_ONLY_PROPERTIES_BY_NAME =\n            Maps.uniqueIndex(MV_ONLY_PROPERTIES, property -> property.metadata().getName());\n\n    private final List<PropertyMetadata<?>> materializedViewProperties;\n\n    @Inject\n    public IcebergMaterializedViewProperties(IcebergTableProperties tableProperties)\n    {\n        requireNonNull(tableProperties, \"tableProperties is null\");\n","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-iceberg/src/main/java/com/facebook/presto/iceberg/IcebergMaterializedViewProperties.java#L117-L153","documentation":"IcebergMaterializedViewProperties validates MV table properties. The max_snapshots_per_refresh property is parsed as an int and must be strictly positive; a value of zero or negative throws PrestoException INVALID_TABLE_PROPERTY with '%s must be positive, got %d'.","triggerScenarios":"ALTER MATERIALIZED VIEW ... SET PROPERTIES max_snapshots_per_refresh = 0 (or negative), or a CREATE MATERIALIZED VIEW ... WITH (max_snapshots_per_refresh = <=0) statement.","commonSituations":"Copy-pasting a config where the value is meant to be 'unlimited' (using 0); arithmetic/templating bugs producing 0 or negative values; misunderstanding that 0 means 'no limit'.","solutions":["Set the property to a positive integer (e.g. 10) instead of 0 or a negative value","Remove the property entirely to use the default behavior instead of 0","Validate any templated/config-driven value before applying it (coerce and check > 0)","Consult the property definition in IcebergMaterializedViewProperties for the accepted range"],"exampleFix":"// before\nALTER MATERIALIZED VIEW sales.daily_mv SET PROPERTIES max_snapshots_per_refresh = 0;\n// after\nALTER MATERIALIZED VIEW sales.daily_mv SET PROPERTIES max_snapshots_per_refresh = 10;","handlingStrategy":"validation","validationCode":"-- Validate before applying:\n-- ensure the value is an integer > 0\nSELECT IF(CAST(${max_snapshots_per_refresh} AS BIGINT) > 0, 'ok', 'invalid') AS check;\n-- or simply: ALTER ... SET PROPERTIES max_snapshots_per_refresh = 10;","typeGuard":"// application-side guard\nboolean isValidMaxSnapshots(Number v) {\n    return v != null && v.intValue() > 0;\n}","tryCatchPattern":"try {\n    stmt.execute(\"ALTER MATERIALIZED VIEW sales.daily_mv SET PROPERTIES max_snapshots_per_refresh = \" + value);\n} catch (SQLException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"must be positive\")) {\n        // clamp to a positive default or remove the property, then retry\n    } else { throw e; }\n}","preventionTips":["Validate config/templated values (must be > 0) before emitting DDL","Treat 0 as 'use default' by omitting the property, not passing 0","Add unit checks around property-generating code paths","Document accepted ranges for MV properties in runbooks"],"tags":["iceberg","materialized-view","invalid-property","validation"],"backgroundTag":"invalid-table-property","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}