projectdiscovery/katana · error

add edge: action cannot be nil

Error message

add edge: action cannot be nil

What it means

AddEdge in the crawl graph refuses to add an edge whose action attribute is nil, because the edge label is derived from action.String(). Passing a nil action is a programming error by the caller that builds the graph, not a runtime crawl condition.

Source

Thrown at pkg/engine/headless/graph/graph.go:87

		}

		err = g.graph.AddEdge(n.OriginID, n.UniqueID, func(ep *graph.EdgeProperties) {
			ep.Weight = n.Depth
			ep.Attributes = edgeAttrs
		})
		if err != nil {
			if errors.Is(err, graph.ErrEdgeAlreadyExists) {
				return nil
			}
			return errors.Wrapf(err, "could not add edge to graph: source vertex %s", n.OriginID)
		}
	}
	return nil
}

func (g *CrawlGraph) AddEdge(sourceState, targetState string, action *types.Action) error {
	if action == nil {
		return errors.New("add edge: action cannot be nil")
	}
	edgeAttrs := map[string]string{
		"label": action.String(),
	}
	err := g.graph.AddEdge(sourceState, targetState, func(ep *graph.EdgeProperties) {
		ep.Weight = action.Depth
		ep.Attributes = edgeAttrs
	})
	if err != nil {
		if errors.Is(err, graph.ErrEdgeAlreadyExists) {
			return nil
		}
		return errors.Wrap(err, "could not add edge to graph")
	}
	return nil
}

func (g *CrawlGraph) GetPageState(id string) (*types.PageState, error) {

View on GitHub (pinned to e3e742739c)

Solutions

  1. Fix the caller to never pass a nil action; skip or default-initialize the action before AddEdge
  2. Guard call sites with if action == nil { continue } when iterating possibly-empty action slices
  3. Return and propagate the error instead of ignoring it when composing graph updates

Example fix

// before
graph.AddEdge(from, to, action) // panics-free but returns error ignored
// after
if action == nil {
    return nil // skip states with no action
}
if err := graph.AddEdge(from, to, action); err != nil { return err }
Defensive patterns

Strategy: validation

Validate before calling

func safeAddEdge(g *graph.CrawlGraph, from, to string, action *types.Action) error {
    if action == nil { return nil }
    return g.AddEdge(from, to, action)
}

Type guard

func hasAction(a *types.Action) bool { return a != nil }

Try / catch

if err := g.AddEdge(from, to, action); err != nil {
    return fmt.Errorf("add edge %s->%s: %w", from, to, err)
}

Prevention

When it happens

Trigger: Calling CrawlGraph.AddEdge(sourceState, targetState, nil) (graph.go:87) — typically when constructing graph edges from actions that were not properly initialized, or deserialized action structs that ended up nil.

Common situations: Custom code building/inspecting the crawl graph; recovering actions from serialized state where an action pointer is nil; test harnesses stubbing AddEdge with nil actions.

Related errors


AI-assisted analysis of projectdiscovery/katana@e3e742739c (2026-09-03). Data as JSON: /api/errors/4d799237d60f855f. Report an issue: GitHub.