{"record":{"id":"96e24b79806a75a1","repo":"router-for-me/CLIProxyAPI","slug":"source-auth-path-is-empty","errorCode":null,"errorMessage":"source auth path is empty","messagePattern":"source auth path is empty","errorType":"http","errorClass":null,"httpStatus":500,"severity":"warning","filePath":"internal/api/handlers/management/auth_files_fields.go","lineNumber":157,"sourceCode":"\t\t\tcontinue\n\t\t}\n\t\tif !sameAuthFilePath(authAttribute(auth, \"path\"), sourcePath) &&\n\t\t\t!sameAuthFilePath(authAttribute(auth, coreauth.AttributeVirtualSource), sourcePath) {\n\t\t\tcontinue\n\t\t}\n\t\tapplyAuthDisabledState(auth, disabled)\n\t\tauth.UpdatedAt = now\n\t\tif _, errUpdate := h.authManager.Update(ctx, auth); errUpdate != nil {\n\t\t\treturn fmt.Errorf(\"failed to update auth %s: %w\", auth.ID, errUpdate)\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc setSourceAuthFileDisabled(path string, disabled bool) error {\n\tpath = strings.TrimSpace(path)\n\tif path == \"\" {\n\t\treturn fmt.Errorf(\"source auth path is empty\")\n\t}\n\tdata, errRead := os.ReadFile(path)\n\tif errRead != nil {\n\t\treturn errRead\n\t}\n\tmetadata := make(map[string]any)\n\tif len(bytes.TrimSpace(data)) > 0 {\n\t\tif errUnmarshal := json.Unmarshal(data, &metadata); errUnmarshal != nil {\n\t\t\treturn fmt.Errorf(\"invalid auth file: %w\", errUnmarshal)\n\t\t}\n\t}\n\tif metadata == nil {\n\t\tmetadata = make(map[string]any)\n\t}\n\tmetadata[\"disabled\"] = disabled\n\traw, errMarshal := json.Marshal(metadata)\n\tif errMarshal != nil {\n\t\treturn fmt.Errorf(\"marshal auth file: %w\", errMarshal)","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/api/handlers/management/auth_files_fields.go#L139-L175","documentation":"setSourceAuthFileDisabled was called with a path that is empty after trimming. The caller derives the path from the auth's AttributeVirtualSource or fallback \"path\" attribute; an empty result means the target auth record has neither attribute, so there is no file to write and the operation is rejected as a record-shape error rather than guessing a path.","triggerScenarios":"Toggling disabled on a plugin virtual auth whose record lacks both the virtual-source and path attributes (malformed record, or an auth type that never had a backing file); calling the internal helper directly with an untrimmed empty string.","commonSituations":"Auth records created by an older version or a custom synthesizer that omits the path attribute; records loaded from an external store with stripped attributes; upstream bugs that build targetAuth from partial data.","solutions":["Inspect the target auth record's attributes via the management GET endpoint and confirm which attribute should hold its source path","Re-create or repair the credential through the normal login/import flow so path metadata is populated","If the record intentionally has no file, toggle it via the regular auth update endpoint (authManager.Update path) instead of the plugin-virtual-source path","Fix upstream code that constructed the record without setting path/virtual-source"],"exampleFix":"// before\npatchPluginVirtualSourceStatus(ctx, authWithoutPath, true)\n// after: ensure the record carries its source file\nauth.Attributes[\"path\"] = \"/app/auths/plugin-source.json\"\npatchPluginVirtualSourceStatus(ctx, auth, true)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(authAttribute(auth, coreauth.AttributeVirtualSource)) == \"\" &&\n   strings.TrimSpace(authAttribute(auth, \"path\")) == \"\" {\n    return errors.New(\"auth has no source path; use the standard auth update endpoint instead\")\n}","typeGuard":"func hasSourcePath(auth *coreauth.Auth) bool {\n    return auth != nil && (strings.TrimSpace(authAttribute(auth, coreauth.AttributeVirtualSource)) != \"\" ||\n        strings.TrimSpace(authAttribute(auth, \"path\")) != \"\")\n}","tryCatchPattern":null,"preventionTips":["Create plugin source auths only through the import path that records the file path","Validate records include path metadata before registering them"],"tags":["validation","auth","metadata"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}