{"record":{"id":"ed990941a7d5273e","repo":"micro/go-micro","slug":"ap2-mandate-id-is-required","errorCode":null,"errorMessage":"ap2: mandate id is required","messagePattern":"ap2: mandate id is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gateway/a2a/ap2.go","lineNumber":68,"sourceCode":"\n// AP2Verification records mandate verification on an A2A task without mixing in\n// payment-settlement state.\ntype AP2Verification struct {\n\tMandateID string `json:\"mandateId\"`\n\tKind      string `json:\"kind\"`\n\tVerified  bool   `json:\"verified\"`\n\tError     string `json:\"error,omitempty\"`\n}\n\n// NewAP2Keypair returns an Ed25519 keypair suitable for tests or local demos.\nfunc NewAP2Keypair() (ed25519.PublicKey, ed25519.PrivateKey, error) {\n\treturn ed25519.GenerateKey(rand.Reader)\n}\n\n// SignAP2Mandate signs a mandate as a verifiable AP2 credential.\nfunc SignAP2Mandate(m AP2Mandate, keyID string, private ed25519.PrivateKey) (AP2SignedMandate, error) {\n\tif m.ID == \"\" {\n\t\treturn AP2SignedMandate{}, errors.New(\"ap2: mandate id is required\")\n\t}\n\tif m.Kind == \"\" {\n\t\treturn AP2SignedMandate{}, errors.New(\"ap2: mandate kind is required\")\n\t}\n\tif m.IssuedAt.IsZero() {\n\t\tm.IssuedAt = time.Now().UTC()\n\t}\n\tpayload, err := ap2Payload(m)\n\tif err != nil {\n\t\treturn AP2SignedMandate{}, err\n\t}\n\treturn AP2SignedMandate{Mandate: m, KeyID: keyID, Signature: base64.RawURLEncoding.EncodeToString(ed25519.Sign(private, payload))}, nil\n}\n\n// VerifyAP2Mandate verifies a signed mandate credential.\nfunc VerifyAP2Mandate(s AP2SignedMandate, public ed25519.PublicKey) error {\n\tsig, err := base64.RawURLEncoding.DecodeString(s.Signature)\n\tif err != nil {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/gateway/a2a/ap2.go#L50-L86","documentation":"SignAP2Mandate in gateway/a2a/ap2.go validates the AP2Mandate before signing it as a verifiable credential. It refuses to sign when the mandate's ID field is empty, since a credential without a stable identifier cannot be referenced, verified, or audited by the gateway. The signature flow aborts immediately and returns an empty AP2SignedMandate alongside this error.","triggerScenarios":"Calling SignAP2Mandate(m, keyID, private) with an AP2Mandate struct whose ID field is the empty string, typically when the mandate was constructed programmatically without assigning an identifier.","commonSituations":"Building AP2Mandate literals in tests or tooling and forgetting to set ID; code paths that deserialize partial mandates from JSON where the id key was omitted; refactors that renamed a field so the ID assignment was dropped.","solutions":["Assign a unique non-empty ID to the AP2Mandate before calling SignAP2Mandate (e.g. a UUID or request-scoped identifier).","If the mandate comes from JSON input, validate/require the id field at deserialization time and reject empty values early.","Add a unit test or builder that guarantees ID is populated whenever a mandate is created."],"exampleFix":"// before\nm := ap2.AP2Mandate{Kind: \"checkout\", IssuedAt: time.Now()}\nsigned, err := ap2.SignAP2Mandate(m, keyID, priv)\n\n// after\nm := ap2.AP2Mandate{ID: uuid.NewString(), Kind: \"checkout\", IssuedAt: time.Now()}\nsigned, err := ap2.SignAP2Mandate(m, keyID, priv)","handlingStrategy":"validation","validationCode":"if m.ID == \"\" {\n\treturn fmt.Errorf(\"cannot sign mandate: ID must be set\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := ap2.SignAP2Mandate(m, keyID, priv); err != nil {\n\tif strings.Contains(err.Error(), \"mandate id is required\") {\n\t\t// regenerate or reject the mandate\n\t}\n}","preventionTips":["Use a constructor or builder that always assigns an ID (e.g. uuid.NewString()).","Validate mandates at deserialization boundaries before any signing attempt.","Add a table-driven test asserting every mandate fixture has a non-empty ID."],"tags":["ap2","validation","missing-field","signing"],"backgroundTag":"missing-required-argument","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}