{"record":{"id":"116af2c142a09651","repo":"vercel/next.js","slug":"hash-manual-only-makes-sense-with-serializatio","errorCode":null,"errorMessage":"hash = \"manual\" only makes sense with serialization = \"hash\"","messagePattern":"hash = \"manual\" only makes sense with serialization = \"hash\"","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"critical","filePath":"turbopack/crates/turbo-tasks-macros/src/value_macro.rs","lineNumber":292,"sourceCode":"        operation,\n        task_input,\n    } = parse_macro_input!(args as ValueArguments);\n\n    // `serialization = \"hash\"` only makes sense with `cell = \"compare\"` (the default).\n    if matches!(serialization_mode, SerializationMode::Hash)\n        && !matches!(cell_mode, CellMode::Compare)\n    {\n        return syn::Error::new(\n            proc_macro2::Span::call_site(),\n            \"serialization = \\\"hash\\\" only makes sense with cell = \\\"compare\\\" (or default)\",\n        )\n        .to_compile_error()\n        .into();\n    }\n\n    // `hash = \"manual\"` only makes sense with `serialization = \"hash\"`.\n    if manual_hash && !matches!(serialization_mode, SerializationMode::Hash) {\n        return syn::Error::new(\n            proc_macro2::Span::call_site(),\n            \"hash = \\\"manual\\\" only makes sense with serialization = \\\"hash\\\"\",\n        )\n        .to_compile_error()\n        .into();\n    }\n\n    // `evict = \"last\"` only makes sense for `serialization = \"skip\"`: it\n    // says \"re-deriving this cell is expensive\", and re-derivation is the\n    // recovery path only for skip mode. Persistable cells restore from disk\n    // (predictable cost), HashOnly cells short-circuit on unchanged hash.\n    //\n    // `evict = \"never\"` is allowed with any serialization mode — a value\n    // type can be persistable AND hold session-scoped state that must not\n    // leave memory (e.g. `DiskFileSystem` carrying file watchers).\n    if matches!(evict_mode, EvictMode::Last)\n        && !matches!(serialization_mode, SerializationMode::Skip)\n    {","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/vercel/next.js/blob/0ae8c72462952df163f1b1e0726641bc5b40dc93/turbopack/crates/turbo-tasks-macros/src/value_macro.rs#L274-L310","documentation":"Compile-time error from the #[turbo_tasks::value] proc-macro. hash = \"manual\" tells the macro to use a hand-written Hash impl for the value type, but that only has meaning when serialization = \"hash\" (which is what triggers hash-based persistence). Using hash = \"manual\" with any other serialization mode (auto/custom/skip) is meaningless, so the macro rejects it.","triggerScenarios":"Annotating a value type with hash = \"manual\" but a serialization mode other than \"hash\", e.g. #[turbo_tasks::value(serialization = \"auto\", hash = \"manual\")].","commonSituations":"A contributor enabling a manual Hash impl while forgetting to switch serialization to \"hash\"; leftover hash = \"manual\" after changing the serialization mode.","solutions":["Set serialization = \"hash\" so the manual hash is actually used: #[turbo_tasks::value(serialization = \"hash\", hash = \"manual\")].","Or remove hash = \"manual\" if you did not intend hash-based serialization."],"exampleFix":"// before\n#[turbo_tasks::value(serialization = \"auto\", hash = \"manual\")]\nstruct Foo { ... }\n\n// after\n#[turbo_tasks::value(serialization = \"hash\", hash = \"manual\")]\nstruct Foo { ... }","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only set hash = \"manual\" together with serialization = \"hash\".","If you change serialization away from \"hash\", remove any hash = \"manual\" attribute in the same edit.","Treat the macro's attribute set as coupled: hash-manual implies serialization-hash."],"tags":["proc-macro","turbo-tasks","value-attributes","compile-error"],"analyzedSha":"0ae8c72462952df163f1b1e0726641bc5b40dc93","analyzedAt":"2026-08-06T19:44:29.143Z","schemaVersion":2},"datasetVersion":"2026-08-07T02:17:10.218Z"}