{"record":{"id":"15756bd8cbceef48","repo":"clockworklabs/SpacetimeDB","slug":"a-direct-index-must-be-paired-with-a-unique-co","errorCode":null,"errorMessage":"a direct index must be paired with a `#[unique] constraint","messagePattern":"a direct index must be paired with a `#\\[unique\\] constraint","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"crates/bindings-macro/src/table.rs","lineNumber":416,"sourceCode":"        Ok(IndexArg::new(accessor, kind, None))\n    }\n\n    fn validate<'a>(&'a self, table_name: &str, cols: &'a [Column<'a>]) -> syn::Result<ValidatedIndex<'a>> {\n        let find_column = |ident| find_column(cols, ident);\n        let (kind, kind_str) = match &self.kind {\n            IndexType::BTree { columns } => {\n                let cols = columns.iter().map(find_column).collect::<syn::Result<Vec<_>>>()?;\n                (ValidatedIndexType::BTree { cols }, \"btree\")\n            }\n            IndexType::Hash { columns } => {\n                let cols = columns.iter().map(find_column).collect::<syn::Result<Vec<_>>>()?;\n                (ValidatedIndexType::Hash { cols }, \"hash\")\n            }\n            IndexType::Direct { column } => {\n                let col = find_column(column)?;\n\n                if !self.is_unique {\n                    return Err(syn::Error::new(\n                        column.span(),\n                        \"a direct index must be paired with a `#[unique] constraint\",\n                    ));\n                }\n\n                (ValidatedIndexType::Direct { col }, \"direct\")\n            }\n        };\n        let gen_index_name = || {\n            // See crates/schema/src/validate/v9.rs for the format of index names.\n            // It's slightly unnerving that we just trust that component to generate this format correctly,\n            // but what can you do.\n            let cols = kind.columns();\n            let cols = cols.iter().map(|col| col.ident.to_string()).collect::<Vec<_>>();\n            let cols = cols.join(\"_\");\n            format!(\"{table_name}_{cols}_idx_{kind_str}\")\n        };\n","sourceCodeStart":398,"sourceCodeEnd":434,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/bindings-macro/src/table.rs#L398-L434","documentation":"A `direct` index in SpacetimeDB maps each indexed value to at most one row, so it is only meaningful on a column that is also declared `#[unique]`. During index validation, an `IndexType::Direct` found on a column where `is_unique` is false is rejected at that column's span. Non-unique columns should use `btree` or `hash` indexes.","triggerScenarios":"Declaring a direct index — table-level `index = direct(col)` or a column-level direct index — on a column that does not carry `#[unique]`.","commonSituations":"Switching an index from btree/hash to direct without adding the uniqueness constraint; assuming 'direct' is a generic faster index type rather than a unique value-to-row index.","solutions":["Add `#[unique]` to the column the direct index targets","If the column's values are not actually unique, switch the index to `btree` or `hash`","Verify existing data satisfies uniqueness before publishing, otherwise inserts will fail at runtime"],"exampleFix":"// before\n#[spacetimedb::table(accessor = user)]\nstruct User {\n    #[index(direct)]\n    email: String,\n}\n\n// after\n#[spacetimedb::table(accessor = user)]\nstruct User {\n    #[unique]\n    #[index(direct)]\n    email: String,\n}","handlingStrategy":"validation","validationCode":"# every direct index must sit on a #[unique] column — review each hit\ngrep -rn 'direct' src/ | grep -v unique || echo OK","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat `direct` as shorthand for a unique index: always pair it with #[unique]","Default to btree or hash; reach for direct only for value-to-row lookups","After adding indexes, read the build output's index list to confirm the intended constraints"],"tags":["rust","proc-macro","spacetimedb","index","unique","compile-time"],"backgroundTag":"schema-constraint-violation","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}