goharbor/harbor · error
missing custom token/key data
Error message
missing custom token/key data
What it means
CustomAuthHandler.Authorize rejects a preheat request when the provider instance uses CUSTOM auth mode but the credential data map is empty — there is no header name/value to set. As with the basic handler, it takes the FIRST key of the map as the HTTP header name and its value as the header value.
Source
Thrown at src/pkg/p2p/preheat/provider/auth/custom_handler.go:40
// CustomAuthHandler handle the custom auth mode.
type CustomAuthHandler struct {
*BaseHandler
}
// Mode implements @Handler.Mode
func (c *CustomAuthHandler) Mode() string {
return AuthModeCustom
}
// Authorize implements @Handler.Authorize
func (c *CustomAuthHandler) Authorize(req *http.Request, cred *Credential) error {
if err := c.BaseHandler.Authorize(req, cred); err != nil {
return err
}
if len(cred.Data) == 0 {
return errors.New("missing custom token/key data")
}
key := reflect.ValueOf(cred.Data).MapKeys()[0].String()
req.Header.Set(key, cred.Data[key])
return nil
}
View on GitHub (pinned to 7b2fd08cc5)
Solutions
- Re-save the instance with auth_info containing the header name as key and the token as value: {"auth_mode": "CUSTOM", "auth_info": {"X-API-Key": "abc123"}}.
- Ensure exactly the intended single entry, since only the first map key is used.
- If the provider truly needs no auth, use auth_mode "NONE".
Example fix
# before
curl -X POST https://harbor/api/v2.0/p2p/preheat/instances -d '{"name": "kraken", "provider": "kraken", "endpoint": "https://kraken.example.com", "auth_mode": "CUSTOM", "auth_info": {}}'
# after
curl -X POST https://harbor/api/v2.0/p2p/preheat/instances -d '{"name": "kraken", "provider": "kraken", "endpoint": "https://kraken.example.com", "auth_mode": "CUSTOM", "auth_info": {"X-API-Key": "abc123"}}' Defensive patterns
Strategy: validation
Validate before calling
function validateCustomAuthInfo(authInfo) {
const entries = Object.entries(authInfo || {});
if (entries.length !== 1) throw new Error('CUSTOM auth requires exactly one {headerName: headerValue} entry');
const [k, v] = entries[0];
if (!/^X-[A-Za-z-]+$|^Authorization$/.test(k) || !v) throw new Error('invalid header key/value');
} Type guard
function isCustomCredValid(cred) {
return cred != null && cred.Data != null && Object.keys(cred.Data).length > 0;
} Try / catch
On 'missing custom token/key data', fix the instance's auth_info to a single {headerName: value} entry via PUT, then trigger a fresh policy execution. Prevention
- CUSTOM auth = one map entry: key is the header name (e.g. X-API-Key), value is the header value.
- Send auth_info as a JSON object, never a string.
- Add schema validation for provider instance payloads in IaC.
When it happens
Trigger: A preheat instance registered with auth_mode "CUSTOM" and empty/missing auth_info; auth_info present but not deserializing into map[string]string; any policy execution against that instance fails at the first authorized request.
Common situations: Providers secured by a static API-key header (e.g. X-API-Key) where the key was never entered; storing auth_info as "X-API-Key: abc" (a string) instead of an object; instance updated later and auth_info wiped.
Related errors
- missing username and/or password
- no credential data provided
- missing OAuth token
- Unauthorized
- BAD_REQUEST
AI-assisted analysis of goharbor/harbor@7b2fd08cc5 (2026-08-16).
Data as JSON: /api/errors/519c893b1714af38.
Report an issue: GitHub.