{"id":"75f2e0bf13f977b5","repo":"rust-lang/rust","slug":"cannot-export-more-than-u32-max-files","errorCode":null,"errorMessage":"cannot export more than U32_MAX files","messagePattern":"cannot export more than U32_MAX files","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"compiler/rustc_metadata/src/rmeta/encoder.rs","lineNumber":330,"sourceCode":"            //\n            // All of this logic ensures that the final result of deserialization is a 'normal'\n            // Span that can be used without any additional trouble.\n            let metadata_index = {\n                // Introduce a new scope so that we drop the 'read()' temporary\n                match &*source_file.external_src.read() {\n                    ExternalSource::Foreign { metadata_index, .. } => *metadata_index,\n                    src => panic!(\"Unexpected external source {src:?}\"),\n                }\n            };\n\n            (SpanKind::Foreign, metadata_index)\n        } else {\n            // Record the fact that we need to encode the data for this `SourceFile`\n            let source_files =\n                s.required_source_files.as_mut().expect(\"Already encoded SourceMap!\");\n            let (metadata_index, _) = source_files.insert_full(source_file_index);\n            let metadata_index: u32 =\n                metadata_index.try_into().expect(\"cannot export more than U32_MAX files\");\n\n            (SpanKind::Local, metadata_index)\n        };\n\n        // Encode the start position relative to the file start, so we profit more from the\n        // variable-length integer encoding.\n        let lo = self.lo - source_file.start_pos;\n\n        // Encode length which is usually less than span.hi and profits more\n        // from the variable-length integer encoding that we use.\n        let len = self.hi - self.lo;\n\n        let tag = SpanTag::new(kind, ctxt, len.0 as usize);\n        tag.encode(s);\n        if tag.context().is_none() {\n            ctxt.encode(s);\n        }\n        lo.encode(s);","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_metadata/src/rmeta/encoder.rs#L312-L348","documentation":"Thrown in rustc's rmeta encoder while serializing a local SourceFile's span: the per-crate metadata index assigned to a SourceFile must fit in a u32 (encoder.rs:330 narrows a usize via try_into().expect()). The compiler allocates one index per distinct SourceFile in the crate's SourceMap, and u32::MAX (~4.29 billion) is the hard ceiling the on-disk format can address. Hitting it means the bookkeeping produced more source files than the format can represent.","triggerScenarios":"A single crate records more than u32::MAX distinct SourceFile entries during `encode_span` / source-map population — e.g. pathological macro/codegen that mints a new SourceFile per iteration, `include!`/`include_str!` driven loops, or a proc-macro that synthesizes vast numbers of named spans. Practically only reproducible with generated builds far beyond normal scale.","commonSituations":"Not hit by normal projects. Seen (if ever) with extreme code generation, build-script-driven mass file emission, or as a symptom of a compiler bug double-counting SourceFiles. A clean rebuild typically reveals it is not a steady-state limit a real codebase reaches.","solutions":["Reduce the number of distinct source files the crate feeds to the compiler (deduplicate generated files, avoid per-iteration `include!`/`concat!` patterns that mint new SourceFiles).","If the count is genuinely that high, split the crate so each crate stays well under u32::MAX files.","Confirm it is not a double-registration bug by checking whether the panic reproduces after `cargo clean`; if counts look sane in a small repro, file a rustc issue with the repro.","As a last resort on a debug build, verify SourceMap growth is not being driven by an internal leak."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn exported_file_count_within_u32(count: usize) -> bool {\n    count <= u32::MAX as usize\n}\n// before invoking any bulk-export/encode path:\nassert!(\n    exported_file_count_within_u32(crate_files.len()),\n    \"rustc_metadata cannot encode more than u32::MAX files; got {}\",\n    crate_files.len()\n);","typeGuard":"// rmeta encodes file indices as u32; guard every external index.\nfn is_valid_rmeta_file_index(i: usize) -> bool {\n    i < u32::MAX as usize\n}","tryCatchPattern":null,"preventionTips":["Cap the number of source modules / generated files in a single crate well below u32::MAX (in practice below ~4 billion; real projects hit unrelated limits first, but codegen/script generators that emit millions of files can approach this).","Split large generated crates into multiple smaller crates rather than one mega-crate.","If you drive rustc programmatically via the metadata encoder API, pre-aggregate and count the file set before calling the encoder and abort with a clear message rather than letting rustc panic.","Never feed synthesized/compiled metadata whose file table you did not construct yourself."],"tags":["rustc","metadata","encoder","limits"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}