{"record":{"id":"8f6f4bfa5c258f9a","repo":"JuliusBrussee/caveman","slug":"cachebench-invalid-corpus","errorCode":null,"errorMessage":"cachebench: invalid corpus","messagePattern":"cachebench: invalid corpus","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cacheengine/cachebench/corpus.go","lineNumber":445,"sourceCode":"\thash := sha256.New()\n\tencoder := json.NewEncoder(hash)\n\tencoder.SetEscapeHTML(false)\n\tfor _, row := range rows {\n\t\t_ = encoder.Encode(row)\n\t}\n\treturn hex.EncodeToString(hash.Sum(nil))\n}\n\n// RunCorpus evaluates one validated public corpus across provider compilers.\nfunc RunCorpus(ctx context.Context, engine *cacheengine.Engine, corpus AgentCorpus, providers []ProviderConfig, target Target) (Report, error) {\n\tif engine == nil {\n\t\treturn Report{}, errors.New(\"cachebench: nil cache engine\")\n\t}\n\tif err := validateTarget(target); err != nil {\n\t\treturn Report{}, err\n\t}\n\tif len(corpus.Rows) == 0 || corpus.SHA256 == \"\" || strings.TrimSpace(corpus.Metadata.Name) == \"\" {\n\t\treturn Report{}, errors.New(\"cachebench: invalid corpus\")\n\t}\n\tif len(providers) == 0 {\n\t\treturn Report{}, errors.New(\"cachebench: no providers\")\n\t}\n\tif len(providers) > 1024 {\n\t\treturn Report{}, errors.New(\"cachebench: provider population exceeds 1024\")\n\t}\n\tcounter := tokens.Default()\n\tcachedCounter := &corpusTokenCounter{Counter: counter, counts: map[[sha256.Size]byte]int{}}\n\tsummary, err := analyzeCorpus(corpus, cachedCounter)\n\tif err != nil {\n\t\treturn Report{}, err\n\t}\n\tscenario := Scenario{Name: \"public-agent-corpus\", Turns: len(corpus.Rows), Step: time.Second, AssumedTTL: 5 * time.Minute}\n\treport := baseReport(BasisCorpusSimulated, scenario, target, QualityEquivalence)\n\treport.Corpus = &summary\n\treport.Scenario.TokenBasis = counter.Name() + \" estimate over normalized OpenAI messages\"\n\treport.Scenario.Step = \"corpus pre_gap\"","sourceCodeStart":427,"sourceCodeEnd":463,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/cacheengine/cachebench/corpus.go#L427-L463","documentation":"RunCorpus validates the corpus shape before doing any work: it must contain at least one row, a non-empty SHA256 digest, and a non-empty trimmed Metadata.Name. Any of these missing yields 'cachebench: invalid corpus', since a benchmark over an empty or unidentifiable corpus is meaningless.","triggerScenarios":"Passing an AgentCorpus with empty Rows, empty SHA256, or whitespace-only Metadata.Name to RunCorpus. Typical after a load/parse step produced an empty struct or the digest step was skipped when building the corpus.","commonSituations":"Corpus loaded from a JSON file that failed silently or was empty; SHA256 computed into a different field or never assigned; Metadata left zero-valued in a hand-built corpus.","solutions":["Verify the corpus source file actually decoded (len(Rows) > 0) before benchmarking","Populate corpus.SHA256 with the hex sha256 of the canonical row encoding and set Metadata.Name to a real identifier","Log corpus.Rows/Sessions counts right after load to catch empty inputs early"],"exampleFix":"// before\ncorpus := AgentCorpus{} // decoded from empty file\nreport, err := cachebench.RunCorpus(ctx, engine, corpus, providers, target)\n\n// after\nif len(corpus.Rows) == 0 || corpus.SHA256 == \"\" || strings.TrimSpace(corpus.Metadata.Name) == \"\" {\n    return fmt.Errorf(\"corpus not ready: rows=%d sha=%q\", len(corpus.Rows), corpus.SHA256)\n}\nreport, err := cachebench.RunCorpus(ctx, engine, corpus, providers, target)","handlingStrategy":"validation","validationCode":"func corpusReady(c AgentCorpus) bool {\n    return len(c.Rows) > 0 && c.SHA256 != \"\" && strings.TrimSpace(c.Metadata.Name) != \"\"\n}\n\nif !corpusReady(corpus) {\n    return fmt.Errorf(\"corpus incomplete: rows=%d sha256_set=%v name=%q\", len(corpus.Rows), corpus.SHA256 != \"\", corpus.Metadata.Name)\n}","typeGuard":"func isValidCorpus(c AgentCorpus) bool {\n    return len(c.Rows) > 0 && c.SHA256 != \"\" && strings.TrimSpace(c.Metadata.Name) != \"\"\n}","tryCatchPattern":"if err := runCorpusWrapper(); err != nil {\n    if strings.Contains(err.Error(), \"invalid corpus\") {\n        // re-check corpus fields and reload/regenerate the corpus file\n    }\n}","preventionTips":["Compute SHA256 and set Metadata.Name in the same function that assembles rows, so finalization cannot be skipped","Assert row count > 0 immediately after decoding the corpus file","Treat an invalid corpus as a build-stage failure with field-level diagnostics, not a runtime surprise"],"tags":["go","corpus","validation","input-validation"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}