Frappe.desk.search.search_link is not whitelisted

My doctype name is vapp. It has one child table(multipleopp). My child doctype(multipleopp) has one field id, it is a link field to another doctype(opp). I created a webform (vapp_form) to collect data anonymously. In Web Form settings i checked Anonymous.

The user cannot pick the values in multipleopp child table if they have not logged in. It throws

frappe.exceptions.PermissionError: You are not permitted to access this resource.Function frappe.desk.search.search_link is not whitelisted

I created webform (vapp_form) in my custom app and my Version:

ERPNext: v14.58.1 (version-14)

Frappe Framework: v14.62.1 (version-14)

The error from the following code

/home/frappe/frappe-bench/apps/frappe/frappe/handler.py

def execute_cmd(cmd, from_async=False):
    """execute a request as python module"""
    for hook in frappe.get_hooks("override_whitelisted_methods", {}).get(cmd, []):
        # override using the first hook
        cmd = hook
        break

    # via server script
    server_script = get_server_script_map().get("_api", {}).get(cmd)
    if server_script:
        return run_server_script(server_script)

    try:
        method = get_attr(cmd)
    except Exception as e:
        frappe.throw(_("Failed to get method for command {0} with {1}").format(cmd, e))

    if from_async:
        method = method.queue

    if method != run_doc_method:        
        is_whitelisted(method)
        is_valid_http_method(method)

    return frappe.call(method, **frappe.form_dict)

The problem is allow_guest=True is not set in search_link - @frappe.whitelist(allow_guest=True). How to set @frappe.whitelist(allow_guest=True) for the particular doctype.

/home/frappe/frappe-bench/apps/frappe/frappe/desk/search.py

@frappe.whitelist()

def search_link(
    doctype,
    txt,
    query=None,
    filters=None,
    page_length=20,
    searchfield=None,
    reference_doctype=None,
    ignore_user_permissions=False,
):
    search_widget(
        doctype,
        txt.strip(),
        query,
        searchfield=searchfield,
        page_length=page_length,
        filters=filters,
        reference_doctype=reference_doctype,
        ignore_user_permissions=ignore_user_permissions,
    )
    print(doctype)
    frappe.response["results"] = build_for_autosuggest(frappe.response["values"], doctype=doctype)
    del frappe.response["values"]

Did you get any solution ?

Heya,

Facing the same issue. Anybody has an idea?
I wonder if we could override the function with a hook in a custom app :thinking:
But I don’t really want to use one…

edit: the function is actually already whitelisted so it should work!

# this is called by the Link Field
@frappe.whitelist()
def search_link(
	doctype: str,
	txt: str,
	query: str | None = None,
	filters: str | dict | list | None = None,
	page_length: int = 10,
	searchfield: str | None = None,
	reference_doctype: str | None = None,
	ignore_user_permissions: bool = False,
) -> list[LinkSearchResults]:

It’s better to create a web portal page and handle this separately. Instead of relying on the search_link endpoint (which is protected and not whitelisted for guest users), it’s better to create a dedicated web portal page that fetches the data server-side and renders it securely for guests.

We followed this approach in our own use case for a Project Registration Form (PRF), where we needed to:

  • Dynamically load data from multiple Doctypes
  • Enable dropdown filtering with search (via Tom Select)
  • Allow guest users to submit form data securely to Frappe backend

`

@frappe.whitelist(allow_guest=True)
def get_context(context):
    # Fetch units for dropdown
    context.units = frappe.get_all(
        "#####",
        fields=["name", "unit_name"],
        order_by="unit_name asc"
    )

    # Fetch filtered people
    allowed_statuses = [
        "#####", "#####"
    ]
    context.people = frappe.get_all(
        "#####",
        filters={"status": ["in", allowed_statuses]},
        fields=["name", "title"],
        order_by="title asc"
    )

    # Fetch countries
    context.countries = frappe.get_all(
        "Country",
        fields=["name"],
        order_by="name asc"
    )
`

This data is then used inside the form like:

<select class="form-control searchable-a">
    {% for person in people %}
        <option value="{{ person.name }}">{{ person.title }}</option>
    {% endfor %}
</select>
1 Like

Ah sweet that looks great, thanks @madhusona!

To add to this, I found another workaround : using an “Autocomplete” field in my form table for which the suggestions work properly.

The downside is you can’t have a dedicated doctype to maintain the list of options so ultimately your approach is more robust.

Cheers :wave:
Antoine,