{"record":{"id":"7db6b7183f28eb33","repo":"OpenNHP/opennhp","slug":"failed-to-decode-evidence-v","errorCode":null,"errorMessage":"failed to decode evidence: %v","messagePattern":"failed to decode evidence: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nhp/core/verifier/verifier.go","lineNumber":59,"sourceCode":"func (f *FallbackVerifier) GetMeasure() string {\n\treturn f.SerialNumber\n}\n\nfunc NewFallbackVerifier(evidence []byte) (*FallbackVerifier, error) {\n\tfallbackVerifier := &FallbackVerifier{}\n\n\terr := json.Unmarshal(evidence, fallbackVerifier)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\treturn fallbackVerifier, nil\n}\n\nfunc NewVerifier(compressedEvienceBase64 string) (Verifier, error) {\n\tcompressedEvidence, err := base64.StdEncoding.DecodeString(compressedEvienceBase64)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to decode evidence: %v\", err)\n\t}\n\n\tr, err := zlib.NewReader(bytes.NewReader(compressedEvidence))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to create zlib reader: %v\", err)\n\t}\n\tdefer r.Close()\n\tevidenceBytes, err := io.ReadAll(r)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to read evidence: %v\", err)\n\t}\n\n\tvar evidence map[string]any\n\n\terr = json.Unmarshal(evidenceBytes, &evidence)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal evidence: %v\", err)\n\t}","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/nhp/core/verifier/verifier.go#L41-L77","documentation":"NewVerifier wraps any base64 decoding failure of its input into \"failed to decode evidence: %v\". The evidence string must be standard (StdEncoding) base64 of zlib-compressed JSON evidence; anything malformed, empty, or URL-safe encoded fails here.","triggerScenarios":"Calling verifier.NewVerifier with a string that is empty, contains non-base64 characters, uses URL-safe base64 padding, or was truncated in transit/storage.","commonSituations":"Evidence passed through JSON/YAML configs with line-wrapping corruption; a js-agent or HTTP client sending URL-safe base64; storing evidence in a DB column that trims '=' padding; passing the raw (unencoded) evidence bytes as a string.","solutions":["Regenerate the evidence at the source with base64.StdEncoding.EncodeToString(zlibCompressed) and re-transmit it","Check for and strip whitespace/newlines introduced by config files or logs before decoding","If the producer uses URL-safe encoding, either switch it to StdEncoding or try base64.RawURLEncoding.DecodeString as a fallback"],"exampleFix":"// before\nverifier, err := NewVerifier(cfg.Evidence) // config value contains '\\n'\n// after\ncleaned := strings.Map(func(r rune) rune { if r=='\\n'||r=='\\r'||r==' ' {return -1}; return r }, cfg.Evidence)\nverifier, err := NewVerifier(cleaned)","handlingStrategy":"validation","validationCode":"if s == \"\" { return errors.New(\"evidence is empty\") }\nif _, err := base64.StdEncoding.DecodeString(strings.TrimSpace(s)); err != nil {\n    return fmt.Errorf(\"evidence is not valid std base64: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if v, err := verifier.NewVerifier(evidenceB64); err != nil {\n    if strings.Contains(err.Error(), \"failed to decode evidence\") {\n        // re-encode or re-request evidence from the agent\n    }\n}","preventionTips":["Always produce evidence with base64.StdEncoding.EncodeToString","Strip whitespace/newlines before decoding","Add a round-trip unit test: encode -> NewVerifier"],"tags":["base64","encoding","attestation","go"],"backgroundTag":"invalid-argument-format","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}