{"record":{"id":"7fd52a66332bcb1e","repo":"goharbor/harbor","slug":"bad-request-7fd52a","errorCode":"BAD_REQUEST","errorMessage":"audit log forward endpoint should be configured before enable skip audit log in database","messagePattern":"audit log forward endpoint should be configured before enable skip audit log in database","errorType":"validation","errorClass":"lib/errors.Error","httpStatus":400,"severity":"warning","filePath":"src/controller/config/controller.go","lineNumber":165,"sourceCode":"}\n\nfunc verifySkipAuditLogCfg(ctx context.Context, cfgs map[string]any, mgr config.Manager) error {\n\tupdated := false\n\tendPoint := mgr.Get(ctx, common.AuditLogForwardEndpoint).GetString()\n\tskipAuditDB := mgr.Get(ctx, common.SkipAuditLogDatabase).GetBool()\n\n\tif skip, exist := cfgs[common.SkipAuditLogDatabase]; exist {\n\t\tskipAuditDB = skip.(bool)\n\t\tupdated = true\n\t}\n\tif endpoint, exist := cfgs[common.AuditLogForwardEndpoint]; exist {\n\t\tendPoint = endpoint.(string)\n\t\tupdated = true\n\t}\n\n\tif updated {\n\t\tif skipAuditDB && len(endPoint) == 0 {\n\t\t\treturn errors.BadRequestError(errors.New(\"audit log forward endpoint should be configured before enable skip audit log in database\"))\n\t\t}\n\t}\n\treturn nil\n}\n\n// verifyValueLengthCfg verifies the cfgs which need to check the value max length to align with frontend.\nfunc verifyValueLengthCfg(_ context.Context, cfgs map[string]any) error {\n\tmaxValue := maxValueLimitedByLength(common.UIMaxLengthLimitedOfNumber)\n\tvalidateCfgs := []string{\n\t\tcommon.TokenExpiration,\n\t\tcommon.RobotTokenDuration,\n\t\tcommon.SessionTimeout,\n\t}\n\n\tfor _, c := range validateCfgs {\n\t\tif v, exist := cfgs[c]; exist {\n\t\t\t// the cfgs is unmarshal from json string, the number type will be float64\n\t\t\tif vf, ok := v.(float64); ok {","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/goharbor/harbor/blob/7b2fd08cc568955cca339afeefab27372840d936/src/controller/config/controller.go#L147-L183","documentation":"When updating Harbor configurations, enabling skip_audit_log_database=true is only legal if an audit_log_forward_endpoint is also set (in the same payload or already persisted). The config controller verifies this pair and returns BAD_REQUEST, because skipping the DB audit sink without a forward endpoint would silently drop audit logs.","triggerScenarios":"PUT /api/v2/configs with {\"skip_audit_log_database\": true} while audit_log_forward_endpoint is absent or sent as an empty string in the same request.","commonSituations":"Migrating audit output to a log forwarder (e.g. syslog endpoint) but enabling the skip flag first; a config-management tool (Terraform/Ansible) sends only the changed key; upgrading to a Harbor version that introduced the flag.","solutions":["Set audit_log_forward_endpoint to a reachable listener address in the same or an earlier update, then set skip_audit_log_database=true.","Verify current values with GET /api/v2/configs and compare with your PUT payload to ensure the endpoint is not being overwritten to empty.","Confirm the forward endpoint actually receives logs after the change, so audits are not lost."],"exampleFix":"# before\nPUT /api/v2/configs\n{\"skip_audit_log_database\": true}\n\n# after\n{\"audit_log_forward_endpoint\": \"127.0.0.1:8514\", \"skip_audit_log_database\": true}","handlingStrategy":"validation","validationCode":"// client-side invariant before PUT /api/v2/configs:\nfunc validateAuditCfg(current, update map[string]any) error {\n    skip := update[\"skip_audit_log_database\"]\n    if skip == nil { skip = current[\"skip_audit_log_database\"] }\n    ep := update[\"audit_log_forward_endpoint\"]\n    if ep == nil { ep = current[\"audit_log_forward_endpoint\"] }\n    if skip == true && (ep == nil || ep == \"\") {\n        return fmt.Errorf(\"set audit_log_forward_endpoint before enabling skip_audit_log_database\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := configCtl.Update(ctx, cfgs, false); err != nil {\n    if liberrors.IsErr(err, liberrors.BadRequestCode) &&\n        strings.Contains(err.Error(), \"audit log forward endpoint\") {\n        // fix payload: add endpoint, resend\n    }\n    return err\n}","preventionTips":["Always send the endpoint key together with skip_audit_log_database.","Read current config first so your update does not blank persisted values.","Codify the pairing in IaC modules with a precondition check."],"tags":["config","audit-log","validation","bad-request"],"backgroundTag":null,"analyzedSha":"7b2fd08cc568955cca339afeefab27372840d936","analyzedAt":"2026-08-16T00:00:10.961Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}