JuliusBrussee/caveman · error
session-value artifact rollback lineage invalid
Error message
session-value artifact rollback lineage invalid
What it means
RollbackParentHash is optional; when set it must be a valid 'sha256:<64 hex>' reference AND must differ from the artifact's own ArtifactHash — a policy cannot claim itself as its rollback parent. This preserves an auditable parent chain so rollbacks point at the artifact that was actually running before.
Source
Thrown at proxy/routing/session_value.go:184
}
if strings.TrimSpace(artifact.OrganizationID) == "" || artifact.OrganizationID != strings.TrimSpace(organizationID) ||
strings.TrimSpace(artifact.ProjectID) == "" || artifact.ProjectID != strings.TrimSpace(projectID) {
return errors.New("session-value artifact tenant scope mismatch")
}
if artifact.PolicyVersion <= 0 || artifact.RouterVersion != SessionValueRouterVersion || strings.TrimSpace(artifact.EstimatorVersion) == "" {
return errors.New("session-value artifact version identity invalid")
}
if !validCompactPoolHash(artifact.CandidatePoolHash) || artifact.CandidatePoolHash != candidatePoolHash {
return errors.New("session-value artifact candidate pool mismatch")
}
if !validSHA256Ref(artifact.TrainingManifestHash) || strings.TrimSpace(artifact.TrainingExtractor) == "" || strings.TrimSpace(artifact.OutcomeContractVersion) == "" {
return errors.New("session-value artifact training lineage invalid")
}
if artifact.ValidFrom.IsZero() || artifact.ValidUntil.IsZero() || !artifact.ValidUntil.After(artifact.ValidFrom) || now.Before(artifact.ValidFrom) || !now.Before(artifact.ValidUntil) {
return errors.New("session-value artifact outside validity window")
}
if artifact.RollbackParentHash != "" && (!validSHA256Ref(artifact.RollbackParentHash) || artifact.RollbackParentHash == artifact.ArtifactHash) {
return errors.New("session-value artifact rollback lineage invalid")
}
if !finite(artifact.QualityUncertaintyZ) || artifact.QualityUncertaintyZ <= 0 || artifact.QualityUncertaintyZ > 5 ||
!finite(artifact.MaxInversePropensity) || artifact.MaxInversePropensity < 1 || artifact.MaxInversePropensity > 100 {
return errors.New("session-value artifact confidence policy invalid")
}
featureNames := SessionValueFeatureNames()
if len(artifact.FeatureSpecs) != len(featureNames) || len(artifact.Actions) == 0 {
return errors.New("session-value artifact has no features or actions")
}
for i, spec := range artifact.FeatureSpecs {
if spec.Name != featureNames[i] || (i > 0 && artifact.FeatureSpecs[i-1].Name >= spec.Name) {
return errors.New("session-value artifact feature vocabulary or order invalid")
}
if spec.Name == "turn_index" && !spec.Required {
return errors.New("session-value artifact must require turn_index")
}
if !finite(spec.Mean) || !finite(spec.Scale) || spec.Scale <= 0 || !finite(spec.Min) || !finite(spec.Max) || spec.Min < 0 || spec.Max < spec.Min {
return fmt.Errorf("session-value feature %q bounds invalid", spec.Name)View on GitHub (pinned to 766dce6b13)
Solutions
- Set RollbackParentHash to the sealed parent artifact's ArtifactHash before calling SealSessionValueArtifact, and re-seal if any field changed afterwards.
- Leave RollbackParentHash empty when the artifact has no rollback parent — it is optional.
- Validate the 'sha256:' + 64 hex format and parent != self at generation time, not just at load time.
Example fix
// before artifact.RollbackParentHash = artifact.ArtifactHash // self-parent: rejected // after artifact.RollbackParentHash = parentArtifact.ArtifactHash // sealed previous artifact artifact, err := routing.SealSessionValueArtifact(artifact) // re-seal after any field change
Defensive patterns
Strategy: validation
Validate before calling
// Before validation (after sealing): parent must be a valid ref and not the artifact itself.
var sha256Ref = regexp.MustCompile(`^sha256:[0-9a-f]{64}$`)
if artifact.RollbackParentHash != "" &&
(!sha256Ref.MatchString(artifact.RollbackParentHash) || artifact.RollbackParentHash == artifact.ArtifactHash) {
return errors.New("rollback parent must reference the sealed previous artifact (sha256:<64 hex>, not itself)")
} Prevention
- Set RollbackParentHash from the sealed parent's ArtifactHash before sealing the child, and re-seal after any field change.
- Leave the field empty when there is no parent rather than guessing a hash.
- Record parent hashes in your deploy log so rollback tooling never copies the wrong value.
When it happens
Trigger: Sealing re-computed the artifact hash after the parent field was copied from the same artifact, making parent == own hash; a truncated or bare-hex parent reference; copy-pasting the wrong hash field into rollback_parent_hash during manual rollback tooling.
Common situations: Automated rollback tooling that sets the parent after sealing (any field change invalidates the old hash); manual artifact surgery; hash-format drift between the tool that records parents and validSHA256Ref.
Related errors
- session-value artifact candidate pool mismatch
- session-value artifact training lineage invalid
- session-value artifact schema mismatch
- session-value artifact tenant scope mismatch
- session-value artifact version identity invalid
AI-assisted analysis of JuliusBrussee/caveman@766dce6b13 (2026-08-18).
Data as JSON: /api/errors/eefa7e27dc29f820.
Report an issue: GitHub.