crowdsecurity/crowdsec · error

attempting to load a new schema for existing ref %s

Error message

attempting to load a new schema for existing ref %s

What it means

RequestValidator keeps one OpenAPI schema per reference name. LoadSchema refuses to register a schema under a ref that already has a loader/schema registered, to prevent silent replacement of a live validation schema. This is a configuration/load-order error, not a schema-content error.

Source

Thrown at pkg/appsec/api_validation/api_validation.go:308

			}
			return fmt.Errorf("unsupported security scheme type %s", input.SecurityScheme.Type)
		}
		if authTokenValue == "" {
			return errors.New("auth token is required but not provided")
		}

		return nil
	}
}

func (rv *RequestValidator) LoadSchema(ref string, schema string, opts *SchemaOptions) error {
	if ref == "" {
		return errors.New("ref cannot be empty")
	}
	rv.logger.Debugf("loading schema for ref %s", ref)

	if _, exists := rv.loaders[ref]; exists {
		return fmt.Errorf("attempting to load a new schema for existing ref %s", ref)
	}

	options := opts.withDefaults()
	if err := options.OnRouteNotFound.validate(); err != nil {
		return fmt.Errorf("on_route_not_found: %w", err)
	}
	if err := options.OnMethodNotAllowed.validate(); err != nil {
		return fmt.Errorf("on_method_not_allowed: %w", err)
	}
	if err := options.OnUnsupportedSecurityScheme.validate(); err != nil {
		return fmt.Errorf("on_unsupported_security_scheme: %w", err)
	}

	loader := openapi3.NewLoader()
	rv.loaders[ref] = loader

	doc, err := loader.LoadFromData([]byte(schema))
	if err != nil {

View on GitHub (pinned to 909b515798)

Solutions

  1. Use a unique ref for each schema (rename one of the two entries).
  2. Create a fresh RequestValidator instance before re-loading schemas (e.g. on reload).
  3. Track which refs are already loaded and skip the second LoadSchema call.
  4. Deduplicate schema entries in the appsec configuration so the same ref is registered once.

Example fix

// before
rv.LoadSchema("myapi", schema1, opts)
rv.LoadSchema("myapi", schema2, opts) // panics: ref exists

// after
rv.LoadSchema("myapi-v1", schema1, opts)
rv.LoadSchema("myapi-v2", schema2, opts)
Defensive patterns

Strategy: validation

Validate before calling

// guard before calling LoadSchema
loaded := map[string]bool{}
func loadOnce(rv *api_validation.RequestValidator, ref, schema string, opts *api_validation.SchemaOptions) error {
    if loaded[ref] {
        return nil // or rebuild validator first
    }
    if err := rv.LoadSchema(ref, schema, opts); err != nil { return err }
    loaded[ref] = true
    return nil
}

Try / catch

if err := rv.LoadSchema(ref, schema, opts); err != nil {
    if strings.Contains(err.Error(), "existing ref") {
        log.Warnf("schema %q already loaded, skipping", ref)
        return nil
    }
    return err
}

Prevention

When it happens

Trigger: Calling LoadSchema twice with the same ref (e.g. two appsec config entries or two loads of the same schema name), or re-calling it after an earlier successful load instead of creating a new RequestValidator.

Common situations: Duplicate schema names in the appsec YAML config; a reload/hot-reload path that calls LoadSchema again on the same validator; looped initialization where startup code runs twice.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/7ff7ffe7b03bda26. Report an issue: GitHub.