fatedier/frp · error

cannot specify both auth.token and auth.tokenSource

Error message

cannot specify both auth.token and auth.tokenSource

What it means

The v1 ConfigValidator's validateAuthTokenSource rejects configs that set both auth.token (a literal token string) and auth.tokenSource (a structured external token provider). The two are mutually exclusive ways to supply the auth token, so specifying both is a configuration contradiction and fails validation before the client or server starts.

Source

Thrown at pkg/config/v1/validation/auth.go:28

// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package validation

import (
	"fmt"

	v1 "github.com/fatedier/frp/pkg/config/v1"
	"github.com/fatedier/frp/pkg/policy/security"
)

func (v *ConfigValidator) validateAuthTokenSource(token string, tokenSource *v1.ValueSource) error {
	var errs error
	// Preserve the previous client/server validation order for joined errors.
	if token != "" && tokenSource != nil {
		errs = AppendError(errs, fmt.Errorf("cannot specify both auth.token and auth.tokenSource"))
	}
	if tokenSource == nil {
		return errs
	}

	if tokenSource.Type == "exec" {
		if err := v.ValidateUnsafeFeature(security.TokenSourceExec); err != nil {
			errs = AppendError(errs, err)
		}
	}
	if err := tokenSource.Validate(); err != nil {
		errs = AppendError(errs, fmt.Errorf("invalid auth.tokenSource: %v", err))
	}
	return errs
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Delete one of the two: keep auth.token for static tokens, or keep auth.tokenSource for external sources.
  2. If migrating to tokenSource, remove the literal token from the config and any secret-injection default that fills it.
  3. Audit included/merged config fragments so only one auth supply mechanism survives the merge.

Example fix

# before
[auth]
token = "abc123"
[auth.tokenSource]
type = "file"
path = "/run/secrets/token"

# after
[auth.tokenSource]
type = "file"
path = "/run/secrets/token"
Defensive patterns

Strategy: validation

Validate before calling

// Reject configs that set both token and tokenSource before loading.
func authNotConflicting(token string, tokenSource *v1.ValueSource) error {
	if token != "" && tokenSource != nil {
		return fmt.Errorf("set either auth.token or auth.tokenSource, not both")
	}
	return nil
}

Type guard

func hasSingleAuthSource(token string, tokenSource *v1.ValueSource) bool {
	return token == "" || tokenSource == nil
}

Prevention

When it happens

Trigger: Running config validation (client load or server load path) with a config containing e.g. [auth] token = "abc" and [auth.tokenSource] type = "file" ... — any non-empty token plus a non-nil tokenSource triggers it. The check fires before tokenSource content is validated.

Common situations: Migrating from static token to tokenSource and forgetting to delete the old token line; templated configs that always emit a default token while also mounting a token source; merging includes/shared snippets that each contribute one of the fields.

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/7bd62b25b723710a. Report an issue: GitHub.