cayleygraph/cayley · error

HTTP Request needed

Error message

HTTP Request needed

What it means

getContext in the Google App Engine datastore QuadStore requires an incoming *http.Request to derive an App Engine context (appengine.NewContext). If the graph.Options map does not contain a non-nil "HTTPRequest" entry, initialization fails and the quadstore cannot talk to the datastore. This is a mandatory option for this backend.

Source

Thrown at graph/gaedatastore/quadstore.go:157

	}
	if _, ok := err.(*datastore.ErrFieldMismatch); ok {
		return true, nil
	}
	if err != nil {
		clog.Warningf("Error occurred when getting quad/node %s %v", k, err)
		return false, err
	}
	// a deleted node should not be returned as found.
	if len(q.Deleted) >= len(q.Added) {
		return false, nil
	}
	return true, nil
}

func getContext(opts graph.Options) (context.Context, error) {
	req := opts["HTTPRequest"].(*http.Request)
	if req == nil {
		err := errors.New("HTTP Request needed")
		clog.Errorf("%v", err)
		return nil, err
	}
	return appengine.NewContext(req), nil
}

func (qs *QuadStore) ForRequest(r *http.Request) (graph.QuadStore, error) {
	return &QuadStore{context: appengine.NewContext(r)}, nil
}

func (qs *QuadStore) NewQuadWriter() (quad.WriteCloser, error) {
	return &quadWriter{qs: qs}, nil
}

type quadWriter struct {
	qs     *QuadStore
	deltas []graph.Delta
}

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Obtain the store from within an HTTP handler and pass the request: opts["HTTPRequest"] = r in the graph.Options map.
  2. If not on App Engine, switch to a different quadstore backend (e.g. bolt, memory) via config instead of gaedatastore.
  3. Verify the option value is exactly *http.Request, not a wrapped or nil value.
  4. Check the appengine SDK import path matches your runtime (google.golang.org/appengine vs legacy appengine).

Example fix

// before
qs, err := graph.NewQuadStore("gaedatastore", "", graph.Options{})
// after (inside an http handler)
qs, err := graph.NewQuadStore("gaedatastore", "", graph.Options{"HTTPRequest": r})
Defensive patterns

Strategy: validation

Validate before calling

if req, ok := opts["HTTPRequest"].(*http.Request); !ok || req == nil {
    return errors.New("gaedatastore requires opts[\"HTTPRequest\"] to be *http.Request")
}

Type guard

func hasHTTPRequest(opts graph.Options) bool {
    r, ok := opts["HTTPRequest"].(*http.Request)
    return ok && r != nil
}

Try / catch

qs, err := graph.NewQuadStore("gaedatastore", "", opts)
if err != nil {
    return fmt.Errorf("gae store init failed: %w", err)
}

Prevention

When it happens

Trigger: Calling gaedatastore.New (via graph.NewQuadStore / cayley config) without passing opts["HTTPRequest"], or passing something other than *http.Request (e.g. nil or wrong type).

Common situations: Running Cayley inside Google App Engine but opening the store outside an HTTP request handler; forgetting to forward the handler's r *http.Request into graph.Options; using an appengine backend in a non-GAE environment.

Understand the failure class

Background: "Must pass :limit option" / "Missing required option" — required option errors explained — this error's family across 41 libraries.

Related errors


AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06). Data as JSON: /api/errors/13923b45a4d0790c. Report an issue: GitHub.